Mercurial > pidgin
annotate finch/finch.c @ 16031:7873f314fadf
Patch in Trac ticket #113 from Simom.
"Continued from patch #1693706 in SF tracker:
Newer Live Messenger -versions doesn't always send SHA1C-field in msnobj's and
so Pidgin discards them. This new version of patch uses sha1c as icon checksum
if it exists, otherwise it falls back to using sha1d, as datallah suggested."
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Mon, 23 Apr 2007 16:28:04 +0000 |
parents | 66dff3dfdea6 |
children | 306b2f0143f8 |
rev | line source |
---|---|
15822 | 1 /** |
15870
66dff3dfdea6
Re-sed the copyright notices so they don't all talk about Purple.
Richard Laager <rlaager@wiktel.com>
parents:
15822
diff
changeset
|
2 * finch |
15822 | 3 * |
15870
66dff3dfdea6
Re-sed the copyright notices so they don't all talk about Purple.
Richard Laager <rlaager@wiktel.com>
parents:
15822
diff
changeset
|
4 * Finch is the legal property of its developers, whose names are too numerous |
15822 | 5 * to list here. Please refer to the COPYRIGHT file distributed with this |
6 * source distribution. | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 #include "account.h" | |
23 #include "conversation.h" | |
24 #include "core.h" | |
25 #include "debug.h" | |
26 #include "eventloop.h" | |
27 #include "ft.h" | |
28 #include "log.h" | |
29 #include "notify.h" | |
30 #include "prefix.h" | |
31 #include "prefs.h" | |
32 #include "prpl.h" | |
33 #include "pounce.h" | |
34 #include "savedstatuses.h" | |
35 #include "sound.h" | |
36 #include "status.h" | |
37 #include "util.h" | |
38 #include "whiteboard.h" | |
39 | |
40 #include "gntdebug.h" | |
41 #include "finch.h" | |
42 #include "gntprefs.h" | |
43 #include "gntui.h" | |
44 #include "gntidle.h" | |
45 | |
46 #define _GNU_SOURCE | |
47 #include <getopt.h> | |
48 | |
49 #include "config.h" | |
50 | |
51 static void | |
52 debug_init() | |
53 { | |
54 finch_debug_init(); | |
55 purple_debug_set_ui_ops(finch_debug_get_ui_ops()); | |
56 } | |
57 | |
58 static PurpleCoreUiOps core_ops = | |
59 { | |
60 finch_prefs_init, | |
61 debug_init, | |
62 gnt_ui_init, | |
63 gnt_ui_uninit | |
64 }; | |
65 | |
66 static PurpleCoreUiOps * | |
67 gnt_core_get_ui_ops() | |
68 { | |
69 return &core_ops; | |
70 } | |
71 | |
72 /* Anything IO-related is directly copied from gtkpurple's source tree */ | |
73 | |
74 #define FINCH_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) | |
75 #define FINCH_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) | |
76 | |
77 typedef struct _PurpleGntIOClosure { | |
78 PurpleInputFunction function; | |
79 guint result; | |
80 gpointer data; | |
81 | |
82 } PurpleGntIOClosure; | |
83 | |
84 static void purple_gnt_io_destroy(gpointer data) | |
85 { | |
86 g_free(data); | |
87 } | |
88 | |
89 static gboolean purple_gnt_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) | |
90 { | |
91 PurpleGntIOClosure *closure = data; | |
92 PurpleInputCondition purple_cond = 0; | |
93 | |
94 if (condition & FINCH_READ_COND) | |
95 purple_cond |= PURPLE_INPUT_READ; | |
96 if (condition & FINCH_WRITE_COND) | |
97 purple_cond |= PURPLE_INPUT_WRITE; | |
98 | |
99 #if 0 | |
100 purple_debug(PURPLE_DEBUG_MISC, "gtk_eventloop", | |
101 "CLOSURE: callback for %d, fd is %d\n", | |
102 closure->result, g_io_channel_unix_get_fd(source)); | |
103 #endif | |
104 | |
105 #ifdef _WIN32 | |
106 if(! purple_cond) { | |
107 #if DEBUG | |
108 purple_debug_misc("gnt_eventloop", | |
109 "CLOSURE received GIOCondition of 0x%x, which does not" | |
110 " match 0x%x (READ) or 0x%x (WRITE)\n", | |
111 condition, FINCH_READ_COND, FINCH_WRITE_COND); | |
112 #endif /* DEBUG */ | |
113 | |
114 return TRUE; | |
115 } | |
116 #endif /* _WIN32 */ | |
117 | |
118 closure->function(closure->data, g_io_channel_unix_get_fd(source), | |
119 purple_cond); | |
120 | |
121 return TRUE; | |
122 } | |
123 | |
124 static guint gnt_input_add(gint fd, PurpleInputCondition condition, PurpleInputFunction function, | |
125 gpointer data) | |
126 { | |
127 PurpleGntIOClosure *closure = g_new0(PurpleGntIOClosure, 1); | |
128 GIOChannel *channel; | |
129 GIOCondition cond = 0; | |
130 | |
131 closure->function = function; | |
132 closure->data = data; | |
133 | |
134 if (condition & PURPLE_INPUT_READ) | |
135 cond |= FINCH_READ_COND; | |
136 if (condition & PURPLE_INPUT_WRITE) | |
137 cond |= FINCH_WRITE_COND; | |
138 | |
139 channel = g_io_channel_unix_new(fd); | |
140 closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, | |
141 purple_gnt_io_invoke, closure, purple_gnt_io_destroy); | |
142 | |
143 g_io_channel_unref(channel); | |
144 return closure->result; | |
145 } | |
146 | |
147 static PurpleEventLoopUiOps eventloop_ops = | |
148 { | |
149 g_timeout_add, | |
150 g_source_remove, | |
151 gnt_input_add, | |
152 g_source_remove, | |
153 NULL /* input_get_error */ | |
154 }; | |
155 | |
156 static PurpleEventLoopUiOps * | |
157 gnt_eventloop_get_ui_ops(void) | |
158 { | |
159 return &eventloop_ops; | |
160 } | |
161 | |
162 /* This is copied from gtkpurple */ | |
163 static char * | |
164 gnt_find_binary_location(void *symbol, void *data) | |
165 { | |
166 static char *fullname = NULL; | |
167 static gboolean first = TRUE; | |
168 | |
169 char *argv0 = data; | |
170 struct stat st; | |
171 char *basebuf, *linkbuf, *fullbuf; | |
172 | |
173 if (!first) | |
174 /* We've already been through this. */ | |
175 return strdup(fullname); | |
176 | |
177 first = FALSE; | |
178 | |
179 if (!argv0) | |
180 return NULL; | |
181 | |
182 | |
183 basebuf = g_find_program_in_path(argv0); | |
184 | |
185 /* But we still need to deal with symbolic links */ | |
186 g_lstat(basebuf, &st); | |
187 while ((st.st_mode & S_IFLNK) == S_IFLNK) { | |
188 int written; | |
189 linkbuf = g_malloc(1024); | |
190 written = readlink(basebuf, linkbuf, 1024 - 1); | |
191 if (written == -1) | |
192 { | |
193 /* This really shouldn't happen, but do we | |
194 * need something better here? */ | |
195 g_free(linkbuf); | |
196 continue; | |
197 } | |
198 linkbuf[written] = '\0'; | |
199 if (linkbuf[0] == G_DIR_SEPARATOR) { | |
200 /* an absolute path */ | |
201 fullbuf = g_strdup(linkbuf); | |
202 } else { | |
203 char *dirbuf = g_path_get_dirname(basebuf); | |
204 /* a relative path */ | |
205 fullbuf = g_strdup_printf("%s%s%s", | |
206 dirbuf, G_DIR_SEPARATOR_S, | |
207 linkbuf); | |
208 g_free(dirbuf); | |
209 } | |
210 /* There's no memory leak here. Really! */ | |
211 g_free(linkbuf); | |
212 g_free(basebuf); | |
213 basebuf = fullbuf; | |
214 g_lstat(basebuf, &st); | |
215 } | |
216 | |
217 fullname = basebuf; | |
218 return strdup(fullname); | |
219 } | |
220 | |
221 | |
222 /* This is mostly copied from gtkpurple's source tree */ | |
223 static void | |
224 show_usage(const char *name, gboolean terse) | |
225 { | |
226 char *text; | |
227 | |
228 if (terse) { | |
229 text = g_strdup_printf(_("%s. Try `%s -h' for more information.\n"), VERSION, name); | |
230 } else { | |
231 text = g_strdup_printf(_("%s\n" | |
232 "Usage: %s [OPTION]...\n\n" | |
233 " -c, --config=DIR use DIR for config files\n" | |
234 " -d, --debug print debugging messages to stdout\n" | |
235 " -h, --help display this help and exit\n" | |
236 " -n, --nologin don't automatically login\n" | |
237 " -v, --version display the current version and exit\n"), VERSION, name); | |
238 } | |
239 | |
240 purple_print_utf8_to_console(stdout, text); | |
241 g_free(text); | |
242 } | |
243 | |
244 static int | |
245 init_libpurple(int argc, char **argv) | |
246 { | |
247 char *path; | |
248 int opt; | |
249 gboolean opt_help = FALSE; | |
250 gboolean opt_nologin = FALSE; | |
251 gboolean opt_version = FALSE; | |
252 char *opt_config_dir_arg = NULL; | |
253 char *opt_session_arg = NULL; | |
254 gboolean debug_enabled = FALSE; | |
255 | |
256 struct option long_options[] = { | |
257 {"config", required_argument, NULL, 'c'}, | |
258 {"debug", no_argument, NULL, 'd'}, | |
259 {"help", no_argument, NULL, 'h'}, | |
260 {"nologin", no_argument, NULL, 'n'}, | |
261 {"session", required_argument, NULL, 's'}, | |
262 {"version", no_argument, NULL, 'v'}, | |
263 {0, 0, 0, 0} | |
264 }; | |
265 | |
266 purple_br_set_locate_fallback_func(gnt_find_binary_location, argv[0]); | |
267 | |
268 #ifdef ENABLE_NLS | |
269 bindtextdomain(PACKAGE, LOCALEDIR); | |
270 bind_textdomain_codeset(PACKAGE, "UTF-8"); | |
271 textdomain(PACKAGE); | |
272 #endif | |
273 | |
274 #ifdef HAVE_SETLOCALE | |
275 setlocale(LC_ALL, ""); | |
276 #endif | |
277 | |
278 /* scan command-line options */ | |
279 opterr = 1; | |
280 while ((opt = getopt_long(argc, argv, | |
281 #ifndef _WIN32 | |
282 "c:dhn::s:v", | |
283 #else | |
284 "c:dhn::v", | |
285 #endif | |
286 long_options, NULL)) != -1) { | |
287 switch (opt) { | |
288 case 'c': /* config dir */ | |
289 g_free(opt_config_dir_arg); | |
290 opt_config_dir_arg = g_strdup(optarg); | |
291 break; | |
292 case 'd': /* debug */ | |
293 debug_enabled = TRUE; | |
294 break; | |
295 case 'h': /* help */ | |
296 opt_help = TRUE; | |
297 break; | |
298 case 'n': /* no autologin */ | |
299 opt_nologin = TRUE; | |
300 break; | |
301 case 's': /* use existing session ID */ | |
302 g_free(opt_session_arg); | |
303 opt_session_arg = g_strdup(optarg); | |
304 break; | |
305 case 'v': /* version */ | |
306 opt_version = TRUE; | |
307 break; | |
308 case '?': /* show terse help */ | |
309 default: | |
310 show_usage(argv[0], TRUE); | |
311 return 0; | |
312 break; | |
313 } | |
314 } | |
315 | |
316 /* show help message */ | |
317 if (opt_help) { | |
318 show_usage(argv[0], FALSE); | |
319 return 0; | |
320 } | |
321 /* show version message */ | |
322 if (opt_version) { | |
323 printf("purple-text %s\n", VERSION); | |
324 return 0; | |
325 } | |
326 | |
327 /* set a user-specified config directory */ | |
328 if (opt_config_dir_arg != NULL) { | |
329 purple_util_set_user_dir(opt_config_dir_arg); | |
330 g_free(opt_config_dir_arg); | |
331 } | |
332 | |
333 /* | |
334 * We're done piddling around with command line arguments. | |
335 * Fire up this baby. | |
336 */ | |
337 | |
338 /* Because we don't want debug-messages to show up and corrup the display */ | |
339 purple_debug_set_enabled(debug_enabled); | |
340 | |
341 purple_core_set_ui_ops(gnt_core_get_ui_ops()); | |
342 purple_eventloop_set_ui_ops(gnt_eventloop_get_ui_ops()); | |
343 purple_idle_set_ui_ops(finch_idle_get_ui_ops()); | |
344 | |
345 path = g_build_filename(purple_user_dir(), "plugins", NULL); | |
346 purple_plugins_add_search_path(path); | |
347 g_free(path); | |
348 | |
349 purple_plugins_add_search_path(LIBDIR); | |
350 | |
351 if (!purple_core_init(FINCH_UI)) | |
352 { | |
353 fprintf(stderr, | |
354 "Initialization of the Purple core failed. Dumping core.\n" | |
355 "Please report this!\n"); | |
356 abort(); | |
357 } | |
358 | |
359 /* TODO: Move blist loading into purple_blist_init() */ | |
360 purple_set_blist(purple_blist_new()); | |
361 purple_blist_load(); | |
362 | |
363 /* TODO: Move prefs loading into purple_prefs_init() */ | |
364 purple_prefs_load(); | |
365 purple_prefs_update_old(); | |
366 | |
367 /* load plugins we had when we quit */ | |
368 purple_plugins_load_saved("/purple/gnt/plugins/loaded"); | |
369 | |
370 /* TODO: Move pounces loading into purple_pounces_init() */ | |
371 purple_pounces_load(); | |
372 | |
373 if (opt_nologin) | |
374 { | |
375 /* Set all accounts to "offline" */ | |
376 PurpleSavedStatus *saved_status; | |
377 | |
378 /* If we've used this type+message before, lookup the transient status */ | |
379 saved_status = purple_savedstatus_find_transient_by_type_and_message( | |
380 PURPLE_STATUS_OFFLINE, NULL); | |
381 | |
382 /* If this type+message is unique then create a new transient saved status */ | |
383 if (saved_status == NULL) | |
384 saved_status = purple_savedstatus_new(NULL, PURPLE_STATUS_OFFLINE); | |
385 | |
386 /* Set the status for each account */ | |
387 purple_savedstatus_activate(saved_status); | |
388 } | |
389 else | |
390 { | |
391 /* Everything is good to go--sign on already */ | |
392 if (!purple_prefs_get_bool("/core/savedstatus/startup_current_status")) | |
393 purple_savedstatus_activate(purple_savedstatus_get_startup()); | |
394 purple_accounts_restore_current_statuses(); | |
395 } | |
396 | |
397 return 1; | |
398 } | |
399 | |
400 int main(int argc, char **argv) | |
401 { | |
402 signal(SIGPIPE, SIG_IGN); | |
403 | |
404 /* Initialize the libpurple stuff */ | |
405 if (!init_libpurple(argc, argv)) | |
406 return 0; | |
407 | |
408 purple_blist_show(); | |
409 gnt_main(); | |
410 | |
411 #ifdef STANDALONE | |
412 purple_core_quit(); | |
413 #endif | |
414 | |
415 return 0; | |
416 } | |
417 |