Mercurial > pidgin-twitter
comparison main.c @ 254:c2620a99622b
- divided the source file into several parts.
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Sat, 22 Nov 2008 18:01:18 +0900 |
parents | pidgin-twitter.c@a37ae6c8fa66 |
children | 9fb8f597adf3 |
comparison
equal
deleted
inserted
replaced
253:a37ae6c8fa66 | 254:c2620a99622b |
---|---|
1 /* | |
2 * Pidgin-Twitter plugin. | |
3 * | |
4 * This program is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU General Public License as | |
6 * published by the Free Software Foundation; either version 2 of the | |
7 * License, or (at your option) any later version. | |
8 * | |
9 * This program is distributed in the hope that it will be useful, but | |
10 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 * General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License | |
15 * along with this program; if not, write to the Free Software | |
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
17 * 02111-1307, USA. | |
18 */ | |
19 #define PURPLE_PLUGINS 1 | |
20 | |
21 #include "pidgin-twitter.h" | |
22 #include "main.h" | |
23 | |
24 /***********/ | |
25 /* globals */ | |
26 /***********/ | |
27 GRegex *regp[NUM_REGPS]; | |
28 static gboolean suppress_oops = FALSE; | |
29 GHashTable *icon_hash[NUM_SERVICES]; | |
30 static GHashTable *conv_hash = NULL; | |
31 static GList *wassr_parrot_list = NULL; | |
32 static GList *identica_parrot_list = NULL; | |
33 #ifdef _WIN32 | |
34 static gboolean blink_state = FALSE; | |
35 static gboolean blink_modified = FALSE; | |
36 #endif | |
37 | |
38 source_t source; | |
39 | |
40 #ifndef _WIN32 | |
41 extern gchar *sanitize_utf(const gchar *msg, gsize len, gsize *newlen) __attribute__ ((weak)); | |
42 #endif | |
43 | |
44 /* prototypes */ | |
45 static gboolean is_twitter_conv(PurpleConversation *conv); | |
46 static gboolean is_wassr_account(PurpleAccount *account, const char *name); | |
47 static gboolean is_wassr_conv(PurpleConversation *conv); | |
48 static gboolean is_identica_account(PurpleAccount *account, const char *name); | |
49 static gboolean is_identica_conv(PurpleConversation *conv); | |
50 static gboolean is_jisko_account(PurpleAccount *account, const char *name); | |
51 static gboolean is_jisko_conv(PurpleConversation *conv); | |
52 static void cleanup_hash_entry_func(gpointer key, gpointer value, gpointer user_data); | |
53 | |
54 static void init_plugin(PurplePlugin *plugin); | |
55 static gboolean load_plugin(PurplePlugin *plugin); | |
56 static gboolean unload_plugin(PurplePlugin *plugin); | |
57 static gboolean sending_im_cb(PurpleAccount *account, char *recipient, char **buffer, void *data); | |
58 static gboolean eval(const GMatchInfo *match_info, GString *result, gpointer user_data); | |
59 static void translate(gchar **str, gint which, gint service); | |
60 static void playsound(gchar **str, gint which); | |
61 static gboolean writing_im_cb(PurpleAccount *account, char *sender, char **buffer, PurpleConversation *conv, int flags, void *data); | |
62 static void insert_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *position, gchar *new_text, gint new_text_length, gpointer user_data); | |
63 static void delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos, GtkTextIter *end_pos, gpointer user_data); | |
64 static void detach_from_conv(PurpleConversation *conv, gpointer null); | |
65 static void delete_requested_icon_marks(PidginConversation *gtkconv, GHashTable *table); | |
66 static void attach_to_conv(PurpleConversation *conv, gpointer null); | |
67 | |
68 | |
69 static void conv_created_cb(PurpleConversation *conv, gpointer null); | |
70 static void deleting_conv_cb(PurpleConversation *conv); | |
71 static gboolean receiving_im_cb(PurpleAccount *account, char **sender, char **buffer, PurpleConversation *conv, PurpleMessageFlags *flags, void *data); | |
72 | |
73 static void remove_marks_func(gpointer key, gpointer value, gpointer user_data); | |
74 static void cancel_fetch_func(gpointer key, gpointer value, gpointer user_data); | |
75 | |
76 static gboolean displaying_im_cb(PurpleAccount *account, const char *who, char **message, PurpleConversation *conv, PurpleMessageFlags flags, void *data); | |
77 static void displayed_im_cb(PurpleAccount *account, const char *who, char *message, PurpleConversation *conv, PurpleMessageFlags flags); | |
78 | |
79 | |
80 | |
81 /*************/ | |
82 /* functions */ | |
83 /*************/ | |
84 | |
85 | |
86 /***********************/ | |
87 /* intrinsic functions */ | |
88 /***********************/ | |
89 static gboolean | |
90 sending_im_cb(PurpleAccount *account, char *recipient, char **buffer, | |
91 void *data) | |
92 { | |
93 int utflen, bytes; | |
94 gboolean twitter_ac = FALSE, wassr_ac = FALSE, identica_ac = FALSE; | |
95 twitter_debug("called\n"); | |
96 | |
97 twitter_ac = is_twitter_account(account, recipient); | |
98 wassr_ac = is_wassr_account(account, recipient); | |
99 identica_ac = is_identica_account(account, recipient); | |
100 | |
101 /* strip all markups */ | |
102 if(twitter_ac || wassr_ac || identica_ac) { | |
103 gchar *tmp, *plain; | |
104 gsize dummy; | |
105 | |
106 tmp = strip_html_markup(*buffer); | |
107 | |
108 #ifndef _WIN32 | |
109 if(sanitize_utf) { | |
110 plain = sanitize_utf(tmp, -1, &dummy); | |
111 g_free(tmp); | |
112 } | |
113 else | |
114 #endif | |
115 plain = tmp; | |
116 | |
117 if(wassr_ac) { | |
118 /* store sending message to address parrot problem */ | |
119 wassr_parrot_list = | |
120 g_list_prepend(wassr_parrot_list, g_strdup(plain)); | |
121 twitter_debug("wassr parrot pushed:%s\n", plain); | |
122 } | |
123 else if(identica_ac) { | |
124 /* store sending message to address parrot problem */ | |
125 identica_parrot_list = | |
126 g_list_prepend(identica_parrot_list, g_strdup(plain)); | |
127 twitter_debug("identica parrot pushed:%s\n", plain); | |
128 } | |
129 | |
130 g_free(*buffer); | |
131 *buffer = g_markup_escape_text(plain, -1); | |
132 g_free(plain); | |
133 } | |
134 | |
135 /* return here if the message is not to twitter */ | |
136 if(!twitter_ac) | |
137 return FALSE; | |
138 | |
139 /* escape pseudo command */ | |
140 if(twitter_ac && | |
141 purple_prefs_get_bool(OPT_ESCAPE_PSEUDO)) { | |
142 escape(buffer); | |
143 } | |
144 | |
145 /* update status with Twitter API instead of IM protocol */ | |
146 if (purple_prefs_get_bool(OPT_API_BASE_POST)) { | |
147 if (buffer && *buffer) { | |
148 post_status_with_api(account, buffer); | |
149 (*buffer)[0] = '\0'; | |
150 } | |
151 return FALSE; | |
152 } | |
153 | |
154 /* try to suppress oops message */ | |
155 utflen = g_utf8_strlen(*buffer, -1); | |
156 bytes = strlen(*buffer); | |
157 twitter_debug("utflen = %d bytes = %d\n", utflen, bytes); | |
158 if(bytes > 140 && utflen <= 140) | |
159 suppress_oops = TRUE; | |
160 | |
161 return FALSE; | |
162 } | |
163 | |
164 static gboolean | |
165 eval(const GMatchInfo *match_info, GString *result, gpointer user_data) | |
166 { | |
167 eval_data *data = (eval_data *)user_data; | |
168 gint which = data->which; | |
169 gint service = data->service; | |
170 gchar sub[SUBST_BUF_SIZE]; | |
171 | |
172 twitter_debug("which = %d service = %d\n", which, service); | |
173 | |
174 if(which == RECIPIENT) { | |
175 gchar *match1 = g_match_info_fetch(match_info, 1); /* preceding \s */ | |
176 gchar *match2 = g_match_info_fetch(match_info, 2); /* recipient */ | |
177 const gchar *format = NULL; | |
178 | |
179 switch(service) { | |
180 case twitter_service: | |
181 format = RECIPIENT_FORMAT_TWITTER; | |
182 break; | |
183 case wassr_service: | |
184 format = RECIPIENT_FORMAT_WASSR; | |
185 break; | |
186 case identica_service: | |
187 format = RECIPIENT_FORMAT_IDENTICA; | |
188 break; | |
189 case jisko_service: | |
190 format = RECIPIENT_FORMAT_JISKO; | |
191 break; | |
192 default: | |
193 twitter_debug("unknown service\n"); | |
194 break; | |
195 } | |
196 g_snprintf(sub, SUBST_BUF_SIZE, format, match1 ? match1: "", match2, match2); | |
197 g_free(match1); | |
198 g_free(match2); | |
199 } | |
200 else if(which == SENDER) { | |
201 gchar *match1 = g_match_info_fetch(match_info, 1); /*preceding CR|LF*/ | |
202 gchar *match2 = g_match_info_fetch(match_info, 2); /* sender */ | |
203 const gchar *format = NULL; | |
204 | |
205 switch(service) { | |
206 case twitter_service: | |
207 format = SENDER_FORMAT_TWITTER; | |
208 break; | |
209 case wassr_service: | |
210 format = SENDER_FORMAT_WASSR; | |
211 break; | |
212 case identica_service: | |
213 format = SENDER_FORMAT_IDENTICA; | |
214 break; | |
215 case jisko_service: | |
216 format = SENDER_FORMAT_JISKO; | |
217 break; | |
218 default: | |
219 twitter_debug("unknown service\n"); | |
220 break; | |
221 } | |
222 | |
223 g_snprintf(sub, SUBST_BUF_SIZE, format, match1 ? match1: "", match2, match2); | |
224 | |
225 g_free(match1); | |
226 g_free(match2); | |
227 } | |
228 else if(which == CHANNEL_WASSR && service == wassr_service) { | |
229 gchar *match1 = g_match_info_fetch(match_info, 1); /*before channel*/ | |
230 gchar *match2 = g_match_info_fetch(match_info, 2); /* channel */ | |
231 const gchar *format = CHANNEL_FORMAT_WASSR; | |
232 | |
233 g_snprintf(sub, SUBST_BUF_SIZE, format, match1 ? match1: "", match2, match2); | |
234 | |
235 g_free(match1); | |
236 g_free(match2); | |
237 } | |
238 else if(which == TAG_IDENTICA && service == identica_service) { | |
239 gchar *match = g_match_info_fetch(match_info, 1); | |
240 gchar *link = g_ascii_strdown(match, -1); | |
241 purple_str_strip_char(link, '-'); | |
242 purple_str_strip_char(link, '_'); | |
243 const gchar *format = TAG_FORMAT_IDENTICA; | |
244 g_snprintf(sub, SUBST_BUF_SIZE, format, link, match); | |
245 g_free(match); | |
246 g_free(link); | |
247 } | |
248 else if(which == EXCESS_LF) { | |
249 g_snprintf(sub, SUBST_BUF_SIZE, "%s", "\n"); | |
250 } | |
251 | |
252 g_string_append(result, sub); | |
253 twitter_debug("sub = %s\n", sub); | |
254 | |
255 return FALSE; | |
256 } | |
257 | |
258 static void | |
259 translate(gchar **str, gint regp_id, gint service) | |
260 { | |
261 gchar *newstr; | |
262 eval_data *data = g_new0(eval_data, 1); | |
263 | |
264 data->which = regp_id; | |
265 data->service = service; | |
266 | |
267 newstr = g_regex_replace_eval(regp[regp_id], /* compiled regex */ | |
268 *str, /* subject string */ | |
269 -1, /* length of the subject string */ | |
270 0, /* start position */ | |
271 0, /* match options */ | |
272 eval, /* function to be called for each match */ | |
273 data, /* user data */ | |
274 NULL); /* error handler */ | |
275 | |
276 g_free(data); data = NULL; | |
277 | |
278 twitter_debug("which = %d *str = %s newstr = %s\n", regp_id, *str, newstr); | |
279 | |
280 g_free(*str); | |
281 *str = newstr; | |
282 } | |
283 | |
284 static void | |
285 playsound(gchar **str, gint which) | |
286 { | |
287 GMatchInfo *match_info; | |
288 const gchar *list = NULL; | |
289 gchar **candidates = NULL, **candidate = NULL; | |
290 | |
291 list = purple_prefs_get_string(which ? OPT_USERLIST_SENDER : | |
292 OPT_USERLIST_RECIPIENT); | |
293 g_return_if_fail(list != NULL); | |
294 if(strstr(list, DEFAULT_LIST)) | |
295 return; | |
296 | |
297 candidates = g_strsplit_set(list, " ,:;", 0); | |
298 g_return_if_fail(candidates != NULL); | |
299 | |
300 g_regex_match(regp[which], *str, 0, &match_info); | |
301 while(g_match_info_matches(match_info)) { | |
302 gchar *user = NULL; | |
303 if(which == RECIPIENT) | |
304 user = g_match_info_fetch(match_info, 2); | |
305 else if(which == SENDER) | |
306 user = g_match_info_fetch(match_info, 2); | |
307 twitter_debug("user = %s\n", user); | |
308 | |
309 for(candidate = candidates; *candidate; candidate++) { | |
310 if(!strcmp(*candidate, "")) | |
311 continue; | |
312 twitter_debug("candidate = %s\n", *candidate); | |
313 if(!strcmp(user, *candidate)) { | |
314 twitter_debug("match. play sound\n"); | |
315 purple_sound_play_event(purple_prefs_get_int | |
316 (which ? OPT_SOUNDID_SENDER : | |
317 OPT_SOUNDID_RECIPIENT), NULL); | |
318 break; | |
319 } | |
320 } | |
321 g_free(user); | |
322 g_match_info_next(match_info, NULL); | |
323 } | |
324 g_strfreev(candidates); | |
325 g_match_info_free(match_info); | |
326 } | |
327 | |
328 static gboolean | |
329 writing_im_cb(PurpleAccount *account, char *sender, char **buffer, | |
330 PurpleConversation *conv, int flags, void *data) | |
331 { | |
332 twitter_debug("called\n"); | |
333 | |
334 gint service = get_service_type(conv); | |
335 | |
336 /* check if the conversation is between twitter */ | |
337 if(service == unknown_service) | |
338 return FALSE; | |
339 | |
340 /* add screen_name if the current message is posted by myself */ | |
341 if (flags & PURPLE_MESSAGE_SEND) { | |
342 gchar *m = NULL; | |
343 const char *screen_name = NULL; | |
344 | |
345 switch(service) { | |
346 case twitter_service: | |
347 screen_name = purple_prefs_get_string(OPT_SCREEN_NAME_TWITTER); | |
348 break; | |
349 case wassr_service: | |
350 screen_name = purple_prefs_get_string(OPT_SCREEN_NAME_WASSR); | |
351 break; | |
352 case identica_service: | |
353 screen_name = purple_prefs_get_string(OPT_SCREEN_NAME_IDENTICA); | |
354 break; | |
355 case jisko_service: | |
356 screen_name = purple_prefs_get_string(OPT_SCREEN_NAME_JISKO); | |
357 break; | |
358 } | |
359 | |
360 if (screen_name) { | |
361 m = g_strdup_printf("%s: %s", screen_name, *buffer); | |
362 g_free(*buffer); | |
363 *buffer = m; | |
364 } | |
365 } | |
366 | |
367 /* strip all markups */ | |
368 strip_markup(buffer, TRUE); | |
369 | |
370 /* playsound */ | |
371 if(purple_prefs_get_bool(OPT_PLAYSOUND_SENDER)) { | |
372 playsound(buffer, SENDER); | |
373 } | |
374 if(purple_prefs_get_bool(OPT_PLAYSOUND_RECIPIENT)) { | |
375 playsound(buffer, RECIPIENT); | |
376 } | |
377 | |
378 /* translate */ | |
379 if(purple_prefs_get_bool(OPT_TRANSLATE_SENDER)) { | |
380 translate(buffer, SENDER, service); | |
381 } | |
382 if(purple_prefs_get_bool(OPT_TRANSLATE_RECIPIENT)) { | |
383 translate(buffer, RECIPIENT, service); | |
384 } | |
385 if(service == wassr_service && | |
386 purple_prefs_get_bool(OPT_TRANSLATE_CHANNEL)) { | |
387 translate(buffer, CHANNEL_WASSR, service); | |
388 } | |
389 if(service == identica_service && | |
390 purple_prefs_get_bool(OPT_TRANSLATE_CHANNEL)) { | |
391 translate(buffer, TAG_IDENTICA, service); | |
392 } | |
393 | |
394 /* escape pseudo command (to show the same result as sending message) */ | |
395 if(service == twitter_service && | |
396 purple_prefs_get_bool(OPT_ESCAPE_PSEUDO)) { | |
397 escape(buffer); | |
398 } | |
399 | |
400 if(purple_prefs_get_bool(OPT_STRIP_EXCESS_LF)) { | |
401 translate(buffer, EXCESS_LF, service); | |
402 } | |
403 | |
404 return FALSE; | |
405 } | |
406 | |
407 static void | |
408 insert_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *position, | |
409 gchar *new_text, gint new_text_length, gpointer user_data) | |
410 { | |
411 PurpleConversation *conv = (PurpleConversation *)user_data; | |
412 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); | |
413 | |
414 GtkWidget *box, *counter = NULL; | |
415 gchar *markup = NULL; | |
416 gint service = get_service_type(conv); | |
417 guint count; | |
418 | |
419 g_return_if_fail(gtkconv != NULL); | |
420 | |
421 switch(service) { | |
422 case twitter_service: | |
423 case identica_service: | |
424 case jisko_service: | |
425 count = gtk_text_buffer_get_char_count(textbuffer) + | |
426 (unsigned int)g_utf8_strlen(new_text, -1); | |
427 markup = g_markup_printf_escaped("<span color=\"%s\">%u</span>", | |
428 count <= 140 ? "black" : "red", count); | |
429 break; | |
430 case wassr_service: | |
431 count = gtk_text_buffer_get_char_count(textbuffer) + | |
432 (unsigned int)g_utf8_strlen(new_text, -1); | |
433 markup = g_markup_printf_escaped("<span color=\"%s\">%u</span>", | |
434 count <= 255 ? "black" : "red", count); | |
435 break; | |
436 default: | |
437 twitter_debug("unknown service\n"); | |
438 break; | |
439 } | |
440 | |
441 box = gtkconv->toolbar; | |
442 counter = g_object_get_data(G_OBJECT(box), PLUGIN_ID "-counter"); | |
443 if(counter) | |
444 gtk_label_set_markup(GTK_LABEL(counter), markup); | |
445 | |
446 g_free(markup); | |
447 } | |
448 | |
449 static void | |
450 delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos, | |
451 GtkTextIter *end_pos, gpointer user_data) | |
452 { | |
453 PurpleConversation *conv = (PurpleConversation *)user_data; | |
454 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); | |
455 GtkWidget *box, *counter = NULL; | |
456 gchar *markup = NULL; | |
457 gint service = get_service_type(conv); | |
458 guint count = 0; | |
459 | |
460 g_return_if_fail(gtkconv != NULL); | |
461 | |
462 switch(service) { | |
463 case twitter_service: | |
464 case identica_service: | |
465 case jisko_service: | |
466 count= gtk_text_buffer_get_char_count(textbuffer) - | |
467 (gtk_text_iter_get_offset(end_pos) - | |
468 gtk_text_iter_get_offset(start_pos)); | |
469 markup = g_markup_printf_escaped("<span color=\"%s\">%u</span>", | |
470 count <= 140 ? "black" : "red", count); | |
471 break; | |
472 case wassr_service: | |
473 count= gtk_text_buffer_get_char_count(textbuffer) - | |
474 (gtk_text_iter_get_offset(end_pos) - | |
475 gtk_text_iter_get_offset(start_pos)); | |
476 markup = g_markup_printf_escaped("<span color=\"%s\">%u</span>", | |
477 count <= 255 ? "black" : "red", count); | |
478 break; | |
479 default: | |
480 twitter_debug("unknown service\n"); | |
481 break; | |
482 } | |
483 | |
484 box = gtkconv->toolbar; | |
485 counter = g_object_get_data(G_OBJECT(box), PLUGIN_ID "-counter"); | |
486 if(counter) | |
487 gtk_label_set_markup(GTK_LABEL(counter), markup); | |
488 | |
489 g_free(markup); | |
490 } | |
491 | |
492 void | |
493 detach_from_window(void) | |
494 { | |
495 GList *list; | |
496 | |
497 /* find twitter conv window out and detach from that */ | |
498 for(list = pidgin_conv_windows_get_list(); list; list = list->next) { | |
499 PidginWindow *win = list->data; | |
500 PurpleConversation *conv = | |
501 pidgin_conv_window_get_active_conversation(win); | |
502 gint service = get_service_type(conv); | |
503 switch(service) { | |
504 case twitter_service: | |
505 case wassr_service: | |
506 case identica_service: | |
507 case jisko_service: | |
508 detach_from_conv(conv, NULL); | |
509 break; | |
510 default: | |
511 twitter_debug("unknown service\n"); | |
512 break; | |
513 } | |
514 } | |
515 } | |
516 | |
517 static void | |
518 detach_from_conv(PurpleConversation *conv, gpointer null) | |
519 { | |
520 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); | |
521 GtkWidget *box, *counter = NULL, *sep = NULL; | |
522 | |
523 g_signal_handlers_disconnect_by_func(G_OBJECT(gtkconv->entry_buffer), | |
524 (GFunc) insert_text_cb, conv); | |
525 g_signal_handlers_disconnect_by_func(G_OBJECT(gtkconv->entry_buffer), | |
526 (GFunc) delete_text_cb, conv); | |
527 | |
528 box = gtkconv->toolbar; | |
529 | |
530 /* remove counter */ | |
531 counter = g_object_get_data(G_OBJECT(box), PLUGIN_ID "-counter"); | |
532 if(counter) { | |
533 gtk_container_remove(GTK_CONTAINER(box), counter); | |
534 g_object_unref(counter); | |
535 g_object_set_data(G_OBJECT(box), PLUGIN_ID "-counter", NULL); | |
536 } | |
537 | |
538 /* remove separator */ | |
539 sep = g_object_get_data(G_OBJECT(box), PLUGIN_ID "-sep"); | |
540 if(sep) { | |
541 gtk_container_remove(GTK_CONTAINER(box), sep); | |
542 g_object_unref(sep); | |
543 g_object_set_data(G_OBJECT(box), PLUGIN_ID "-sep", NULL); | |
544 } | |
545 | |
546 gtk_widget_queue_draw(pidgin_conv_get_window(gtkconv)->window); | |
547 } | |
548 | |
549 static void | |
550 remove_marks_func(gpointer key, gpointer value, gpointer user_data) | |
551 { | |
552 icon_data *data = (icon_data *)value; | |
553 GtkTextBuffer *text_buffer = (GtkTextBuffer *)user_data; | |
554 GList *mark_list = NULL; | |
555 GList *current; | |
556 | |
557 if(!data) | |
558 return; | |
559 | |
560 if(data->request_list) | |
561 mark_list = data->request_list; | |
562 | |
563 /* remove the marks in its GtkTextBuffers */ | |
564 current = g_list_first(mark_list); | |
565 while(current) { | |
566 GtkTextMark *current_mark = current->data; | |
567 GtkTextBuffer *current_text_buffer = | |
568 gtk_text_mark_get_buffer(current_mark); | |
569 GList *next; | |
570 | |
571 next = g_list_next(current); | |
572 | |
573 if(!current_text_buffer) | |
574 continue; | |
575 | |
576 if(text_buffer) { | |
577 if(current_text_buffer == text_buffer) { | |
578 /* the mark will be freed in this function */ | |
579 gtk_text_buffer_delete_mark(current_text_buffer, | |
580 current_mark); | |
581 current->data = NULL; | |
582 mark_list = g_list_delete_link(mark_list, current); | |
583 } | |
584 } | |
585 else { | |
586 gtk_text_buffer_delete_mark(current_text_buffer, current_mark); | |
587 current->data = NULL; | |
588 mark_list = g_list_delete_link(mark_list, current); | |
589 } | |
590 | |
591 current = next; | |
592 } | |
593 | |
594 data->request_list = mark_list; | |
595 } | |
596 | |
597 static void | |
598 delete_requested_icon_marks(PidginConversation *conv, GHashTable *table) { | |
599 GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( | |
600 GTK_TEXT_VIEW(conv->imhtml)); | |
601 | |
602 g_hash_table_foreach(table, | |
603 (GHFunc)remove_marks_func, | |
604 (gpointer)text_buffer); | |
605 } | |
606 | |
607 void | |
608 attach_to_window(void) | |
609 { | |
610 GList *list; | |
611 | |
612 twitter_debug("called\n"); | |
613 | |
614 /* find twitter conv window out and attach to that */ | |
615 for(list = pidgin_conv_windows_get_list(); list; list = list->next) { | |
616 PidginWindow *win = list->data; | |
617 PurpleConversation *conv = | |
618 pidgin_conv_window_get_active_conversation(win); | |
619 gint service = get_service_type(conv); | |
620 /* only attach to twitter conversation window */ | |
621 switch(service) { | |
622 case twitter_service: | |
623 case wassr_service: | |
624 case identica_service: | |
625 case jisko_service: | |
626 attach_to_conv(conv, NULL); | |
627 break; | |
628 default: | |
629 twitter_debug("unknown service\n"); | |
630 break; | |
631 } | |
632 } | |
633 } | |
634 | |
635 static void | |
636 attach_to_conv(PurpleConversation *conv, gpointer null) | |
637 { | |
638 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); | |
639 GtkWidget *box, *sep, *counter, *menus; | |
640 GtkIMHtml *imhtml; | |
641 | |
642 box = gtkconv->toolbar; | |
643 imhtml = GTK_IMHTML(gtkconv->imhtml); | |
644 | |
645 /* Disable widgets that decorate or add link to composing text | |
646 * because Twitter cannot receive marked up string. For lean-view | |
647 * and wide-view, see pidgin/gtkimhtmltoolbar.c. | |
648 */ | |
649 menus = g_object_get_data(G_OBJECT(box), "lean-view"); | |
650 if(menus) { | |
651 gtk_widget_set_sensitive(GTK_WIDGET(menus), FALSE); | |
652 } | |
653 menus = g_object_get_data(G_OBJECT(box), "wide-view"); | |
654 if(menus) { | |
655 gtk_widget_set_sensitive(GTK_WIDGET(menus), FALSE); | |
656 } | |
657 | |
658 purple_conversation_set_features( | |
659 gtkconv->active_conv, | |
660 purple_conversation_get_features(gtkconv->active_conv) & | |
661 ~PURPLE_CONNECTION_HTML); | |
662 | |
663 /* check if the counter is enabled */ | |
664 if(!purple_prefs_get_bool(OPT_COUNTER)) | |
665 return; | |
666 | |
667 /* get counter object */ | |
668 counter = g_object_get_data(G_OBJECT(box), PLUGIN_ID "-counter"); | |
669 g_return_if_fail(counter == NULL); | |
670 | |
671 /* make counter object */ | |
672 counter = gtk_label_new(NULL); | |
673 gtk_widget_set_name(counter, "counter_label"); | |
674 gtk_label_set_text(GTK_LABEL(counter), "0"); | |
675 gtk_box_pack_end(GTK_BOX(box), counter, FALSE, FALSE, 0); | |
676 gtk_widget_show_all(counter); | |
677 g_object_set_data(G_OBJECT(box), PLUGIN_ID "-counter", counter); | |
678 | |
679 /* make separator object */ | |
680 sep = gtk_vseparator_new(); | |
681 gtk_box_pack_end(GTK_BOX(box), sep, FALSE, FALSE, 0); | |
682 gtk_widget_show_all(sep); | |
683 g_object_set_data(G_OBJECT(box), PLUGIN_ID "-sep", sep); | |
684 | |
685 /* connect to signals */ | |
686 g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "insert_text", | |
687 G_CALLBACK(insert_text_cb), conv); | |
688 g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "delete_range", | |
689 G_CALLBACK(delete_text_cb), conv); | |
690 | |
691 /* redraw window */ | |
692 gtk_widget_queue_draw(pidgin_conv_get_window(gtkconv)->window); | |
693 } | |
694 | |
695 gboolean | |
696 is_twitter_account(PurpleAccount *account, const char *name) | |
697 { | |
698 const gchar *proto = purple_account_get_protocol_id(account); | |
699 | |
700 if(g_strstr_len(name, 19, "twitter@twitter.com") && | |
701 g_strstr_len(proto, 11, "prpl-jabber")) { | |
702 return TRUE; | |
703 } | |
704 | |
705 return FALSE; | |
706 } | |
707 | |
708 static gboolean | |
709 is_twitter_conv(PurpleConversation *conv) | |
710 { | |
711 g_return_val_if_fail(conv != NULL, FALSE); | |
712 | |
713 const char *name = purple_conversation_get_name(conv); | |
714 PurpleAccount *account = purple_conversation_get_account(conv); | |
715 | |
716 return is_twitter_account(account, name); | |
717 } | |
718 | |
719 static gboolean | |
720 is_wassr_account(PurpleAccount *account, const char *name) | |
721 { | |
722 const gchar *proto = purple_account_get_protocol_id(account); | |
723 | |
724 if(g_strstr_len(name, 18, "wassr-bot@wassr.jp") && | |
725 g_strstr_len(proto, 11, "prpl-jabber")) { | |
726 return TRUE; | |
727 } | |
728 | |
729 return FALSE; | |
730 } | |
731 | |
732 static gboolean | |
733 is_wassr_conv(PurpleConversation *conv) | |
734 { | |
735 g_return_val_if_fail(conv != NULL, FALSE); | |
736 | |
737 const char *name = purple_conversation_get_name(conv); | |
738 PurpleAccount *account = purple_conversation_get_account(conv); | |
739 | |
740 return is_wassr_account(account, name); | |
741 } | |
742 | |
743 static gboolean | |
744 is_identica_account(PurpleAccount *account, const char *name) | |
745 { | |
746 const gchar *proto = purple_account_get_protocol_id(account); | |
747 | |
748 if(g_strstr_len(name, 16, "update@identi.ca") && | |
749 g_strstr_len(proto, 11, "prpl-jabber")) { | |
750 return TRUE; | |
751 } | |
752 | |
753 return FALSE; | |
754 } | |
755 | |
756 static gboolean | |
757 is_identica_conv(PurpleConversation *conv) | |
758 { | |
759 g_return_val_if_fail(conv != NULL, FALSE); | |
760 | |
761 const char *name = purple_conversation_get_name(conv); | |
762 PurpleAccount *account = purple_conversation_get_account(conv); | |
763 | |
764 return is_identica_account(account, name); | |
765 } | |
766 | |
767 static gboolean | |
768 is_jisko_account(PurpleAccount *account, const char *name) | |
769 { | |
770 const gchar *proto = purple_account_get_protocol_id(account); | |
771 | |
772 if(g_strstr_len(name, 16, "bot@jisko.net") && | |
773 g_strstr_len(proto, 11, "prpl-jabber")) { | |
774 return TRUE; | |
775 } | |
776 | |
777 return FALSE; | |
778 } | |
779 | |
780 static gboolean | |
781 is_jisko_conv(PurpleConversation *conv) | |
782 { | |
783 g_return_val_if_fail(conv != NULL, FALSE); | |
784 | |
785 const char *name = purple_conversation_get_name(conv); | |
786 PurpleAccount *account = purple_conversation_get_account(conv); | |
787 | |
788 return is_jisko_account(account, name); | |
789 } | |
790 | |
791 gint | |
792 get_service_type_by_account(PurpleAccount *account, const char *sender) | |
793 { | |
794 gint service = unknown_service; | |
795 | |
796 g_return_val_if_fail(account != NULL, unknown_service); | |
797 g_return_val_if_fail(sender != NULL, unknown_service); | |
798 | |
799 if(is_twitter_account(account, sender)) | |
800 service = twitter_service; | |
801 else if(is_wassr_account(account, sender)) | |
802 service = wassr_service; | |
803 else if(is_identica_account(account, sender)) | |
804 service = identica_service; | |
805 else if(is_jisko_account(account, sender)) | |
806 service = jisko_service; | |
807 | |
808 return service; | |
809 } | |
810 | |
811 gint | |
812 get_service_type(PurpleConversation *conv) | |
813 { | |
814 gint service = unknown_service; | |
815 | |
816 g_return_val_if_fail(conv != NULL, unknown_service); | |
817 | |
818 if(is_twitter_conv(conv)) | |
819 service = twitter_service; | |
820 else if(is_wassr_conv(conv)) | |
821 service = wassr_service; | |
822 else if(is_identica_conv(conv)) | |
823 service = identica_service; | |
824 else if(is_jisko_conv(conv)) | |
825 service = jisko_service; | |
826 | |
827 return service; | |
828 } | |
829 | |
830 static void | |
831 conv_created_cb(PurpleConversation *conv, gpointer null) | |
832 { | |
833 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); | |
834 | |
835 twitter_debug("called\n"); | |
836 | |
837 g_return_if_fail(gtkconv != NULL); | |
838 | |
839 gint service = get_service_type(conv); | |
840 /* only attach to twitter conversation window */ | |
841 switch(service) { | |
842 case twitter_service: | |
843 get_status_with_api((gpointer)conv); | |
844 source.id = g_timeout_add_seconds( | |
845 purple_prefs_get_int(OPT_API_BASE_GET_INTERVAL), | |
846 get_status_with_api, (gpointer)conv); | |
847 source.conv = conv; | |
848 attach_to_conv(conv, NULL); | |
849 break; | |
850 case wassr_service: | |
851 case identica_service: | |
852 case jisko_service: | |
853 attach_to_conv(conv, NULL); | |
854 break; | |
855 default: | |
856 twitter_debug("unknown service\n"); | |
857 break; | |
858 } | |
859 } | |
860 | |
861 static void | |
862 deleting_conv_cb(PurpleConversation *conv) | |
863 { | |
864 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); | |
865 | |
866 twitter_debug("called\n"); | |
867 | |
868 g_return_if_fail(gtkconv != NULL); | |
869 | |
870 gint service = get_service_type(conv); | |
871 GHashTable *hash = NULL; | |
872 | |
873 /* only attach to twitter conversation window */ | |
874 switch(service) { | |
875 case twitter_service: | |
876 if(purple_prefs_get_bool(OPT_API_BASE_POST)) { | |
877 g_source_remove_by_user_data((gpointer)conv); | |
878 source.id = 0; | |
879 source.conv = NULL; | |
880 } | |
881 hash = icon_hash[twitter_service]; | |
882 break; | |
883 case wassr_service: | |
884 hash = icon_hash[wassr_service]; | |
885 break; | |
886 case identica_service: | |
887 hash = icon_hash[identica_service]; | |
888 break; | |
889 case jisko_service: | |
890 hash = icon_hash[jisko_service]; | |
891 break; | |
892 default: | |
893 twitter_debug("unknown service\n"); | |
894 break; | |
895 } | |
896 | |
897 if(hash) | |
898 delete_requested_icon_marks(gtkconv, hash); | |
899 } | |
900 | |
901 void | |
902 apply_filter(gchar **sender, gchar **buffer, PurpleMessageFlags *flags, int service) | |
903 { | |
904 GMatchInfo *match_info; | |
905 const gchar *list = NULL; | |
906 gchar *screen_name = NULL; | |
907 gchar **candidates = NULL, **candidate = NULL; | |
908 | |
909 g_return_if_fail(*sender != NULL); | |
910 g_return_if_fail(*buffer != NULL); | |
911 | |
912 gchar *plain = strip_html_markup(*buffer); | |
913 | |
914 switch(service) { | |
915 case twitter_service: | |
916 default: | |
917 list = purple_prefs_get_string(OPT_FILTER_TWITTER); | |
918 screen_name = g_strdup_printf("@%s", purple_prefs_get_string(OPT_SCREEN_NAME_TWITTER)); | |
919 break; | |
920 case wassr_service: | |
921 list = purple_prefs_get_string(OPT_FILTER_WASSR); | |
922 screen_name = g_strdup_printf("@%s", purple_prefs_get_string(OPT_SCREEN_NAME_WASSR)); | |
923 break; | |
924 case identica_service: | |
925 list = purple_prefs_get_string(OPT_FILTER_IDENTICA); | |
926 screen_name = g_strdup_printf("@%s", purple_prefs_get_string(OPT_SCREEN_NAME_IDENTICA)); | |
927 break; | |
928 case jisko_service: | |
929 list = purple_prefs_get_string(OPT_FILTER_JISKO); | |
930 screen_name = g_strdup_printf("@%s", purple_prefs_get_string(OPT_SCREEN_NAME_JISKO)); | |
931 break; | |
932 } | |
933 g_return_if_fail(list != NULL); | |
934 if(strstr(list, DEFAULT_LIST)) | |
935 return; | |
936 | |
937 /* find @myself */ | |
938 if(purple_prefs_get_bool(OPT_FILTER_EXCLUDE_REPLY) && | |
939 strstr(plain, screen_name)) { | |
940 g_free(plain); | |
941 g_free(screen_name); | |
942 return; | |
943 } | |
944 else | |
945 g_free(screen_name); | |
946 | |
947 candidates = g_strsplit_set(list, " ,:;", 0); | |
948 g_return_if_fail(candidates != NULL); | |
949 | |
950 g_regex_match(regp[SENDER], plain, 0, &match_info); | |
951 while(g_match_info_matches(match_info)) { | |
952 gchar *user = NULL; | |
953 user = g_match_info_fetch(match_info, 2); | |
954 twitter_debug("user = %s\n", user); | |
955 | |
956 for(candidate = candidates; *candidate; candidate++) { | |
957 if(!strcmp(*candidate, "")) | |
958 continue; | |
959 twitter_debug("candidate = %s\n", *candidate); | |
960 if(!strcmp(user, *candidate)) { | |
961 twitter_debug("match. filter %s\n", user); | |
962 /* pidgin should handle this flag properly --yaz */ | |
963 // *flags |= PURPLE_MESSAGE_INVISIBLE; | |
964 | |
965 /* temporal workaround */ | |
966 g_free(*sender); *sender = NULL; | |
967 g_free(*buffer); *buffer = NULL; | |
968 break; | |
969 } | |
970 } | |
971 | |
972 g_free(user); | |
973 g_match_info_next(match_info, NULL); | |
974 } | |
975 | |
976 g_free(plain); | |
977 g_strfreev(candidates); | |
978 g_match_info_free(match_info); | |
979 } | |
980 | |
981 | |
982 static gboolean | |
983 receiving_im_cb(PurpleAccount *account, char **sender, char **buffer, | |
984 PurpleConversation *conv, PurpleMessageFlags *flags, void *data) | |
985 { | |
986 twitter_debug("called\n"); | |
987 twitter_debug("buffer = %s suppress_oops = %d\n", *buffer, suppress_oops); | |
988 | |
989 gint service; | |
990 | |
991 service = get_service_type_by_account(account, *sender); | |
992 twitter_debug("service = %d\n", service); | |
993 | |
994 #ifdef _WIN32 | |
995 /* suppress notification of incoming messages. */ | |
996 if(service != unknown_service && | |
997 purple_prefs_get_bool(OPT_PREVENT_NOTIFICATION)) { | |
998 if(!blink_modified) { | |
999 blink_modified = TRUE; | |
1000 blink_state = purple_prefs_get_bool(OPT_PIDGIN_BLINK_IM); | |
1001 purple_prefs_set_bool(OPT_PIDGIN_BLINK_IM, FALSE); | |
1002 } | |
1003 } | |
1004 else { | |
1005 if(blink_modified) { | |
1006 purple_prefs_set_bool(OPT_PIDGIN_BLINK_IM, blink_state); | |
1007 blink_modified = FALSE; | |
1008 } | |
1009 } | |
1010 #endif | |
1011 | |
1012 if(service == wassr_service) { | |
1013 gchar *stripped = strip_html_markup(*buffer); | |
1014 /* suppress annoying completion message from wassr */ | |
1015 if(strstr(*buffer, "<body>チャンネル投稿完了:")) { | |
1016 twitter_debug("clearing channel parrot message\n"); | |
1017 g_free(*sender); *sender = NULL; | |
1018 g_free(*buffer); *buffer = NULL; | |
1019 } | |
1020 /* discard parrot message */ | |
1021 else { | |
1022 GList *current = g_list_first(wassr_parrot_list); | |
1023 while(current) { | |
1024 GList *next = g_list_next(current); | |
1025 | |
1026 if(strstr(stripped, current->data)) { | |
1027 twitter_debug("parrot clearing: buf = %s post = %s\n", | |
1028 *buffer, (char *)current->data); | |
1029 g_free(*sender); *sender = NULL; | |
1030 g_free(*buffer); *buffer = NULL; | |
1031 g_free(current->data); | |
1032 current->data = NULL; | |
1033 wassr_parrot_list = | |
1034 g_list_delete_link(wassr_parrot_list, current); | |
1035 break; | |
1036 } | |
1037 | |
1038 current = next; | |
1039 } | |
1040 } | |
1041 g_free(stripped); | |
1042 } | |
1043 | |
1044 if(service == identica_service) { | |
1045 /* discard parrot message */ | |
1046 gchar *stripped = strip_html_markup(*buffer); | |
1047 GList *current = g_list_first(identica_parrot_list); | |
1048 while(current) { | |
1049 GList *next = g_list_next(current); | |
1050 | |
1051 if(strstr(stripped, current->data)) { | |
1052 twitter_debug("identica parrot clearing: buf = %s post = %s\n", | |
1053 *buffer, (char *)current->data); | |
1054 g_free(*sender); *sender = NULL; | |
1055 g_free(*buffer); *buffer = NULL; | |
1056 g_free(current->data); | |
1057 current->data = NULL; | |
1058 identica_parrot_list = | |
1059 g_list_delete_link(identica_parrot_list, current); | |
1060 break; | |
1061 } | |
1062 | |
1063 current = next; | |
1064 } | |
1065 g_free(stripped); | |
1066 } | |
1067 | |
1068 /* filtering */ | |
1069 if(purple_prefs_get_bool(OPT_FILTER)) { | |
1070 apply_filter(sender, buffer, flags, service); | |
1071 } | |
1072 | |
1073 /* return here if it is not twitter */ | |
1074 if(service != twitter_service) { | |
1075 return FALSE; | |
1076 } | |
1077 | |
1078 /* if we use api, discard all incoming IM messages. */ | |
1079 if(purple_prefs_get_bool(OPT_API_BASE_POST)) { | |
1080 g_free(*sender); *sender = NULL; | |
1081 g_free(*buffer); *buffer = NULL; | |
1082 } | |
1083 | |
1084 if(!suppress_oops || !purple_prefs_get_bool(OPT_SUPPRESS_OOPS)) | |
1085 return FALSE; | |
1086 | |
1087 if(strstr(*buffer, OOPS_MESSAGE)) { | |
1088 twitter_debug("clearing sender and buffer\n"); | |
1089 g_free(*sender); *sender = NULL; | |
1090 g_free(*buffer); *buffer = NULL; | |
1091 suppress_oops = FALSE; | |
1092 } | |
1093 return FALSE; | |
1094 } | |
1095 | |
1096 | |
1097 static gboolean | |
1098 displaying_im_cb(PurpleAccount *account, const char *who, char **message, | |
1099 PurpleConversation *conv, PurpleMessageFlags flags, | |
1100 void *unused) | |
1101 { | |
1102 GtkIMHtml *imhtml; | |
1103 GtkTextBuffer *text_buffer; | |
1104 gint service = get_service_type(conv); | |
1105 gint linenumber = 0; | |
1106 | |
1107 twitter_debug("called\n"); | |
1108 | |
1109 if(service == unknown_service) { | |
1110 twitter_debug("neither twitter nor wassr conv\n"); | |
1111 return FALSE; | |
1112 } | |
1113 | |
1114 /* get text buffer */ | |
1115 imhtml = GTK_IMHTML(PIDGIN_CONVERSATION(conv)->imhtml); | |
1116 text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imhtml)); | |
1117 | |
1118 /* store number of lines */ | |
1119 linenumber = gtk_text_buffer_get_line_count(text_buffer); | |
1120 g_hash_table_insert(conv_hash, conv, GINT_TO_POINTER(linenumber)); | |
1121 twitter_debug("conv = %p linenumber = %d\n", conv, linenumber); | |
1122 | |
1123 return FALSE; | |
1124 } | |
1125 | |
1126 static void | |
1127 displayed_im_cb(PurpleAccount *account, const char *who, char *message, | |
1128 PurpleConversation *conv, PurpleMessageFlags flags) | |
1129 { | |
1130 GMatchInfo *match_info = NULL; | |
1131 gchar *user_name = NULL; | |
1132 GtkIMHtml *imhtml; | |
1133 GtkTextBuffer *text_buffer; | |
1134 GtkTextIter insertion_point; | |
1135 gint service = get_service_type(conv); | |
1136 icon_data *data = NULL; | |
1137 gint linenumber; | |
1138 GHashTable *hash = NULL; | |
1139 gboolean renew = FALSE; | |
1140 | |
1141 twitter_debug("called\n"); | |
1142 | |
1143 if(service == unknown_service) { | |
1144 twitter_debug("unknown service\n"); | |
1145 return; | |
1146 } | |
1147 | |
1148 /* get user's name */ | |
1149 g_regex_match(regp[USER], message, 0, &match_info); | |
1150 if(!g_match_info_matches(match_info)) { | |
1151 twitter_debug("message was not matched : %s\n", message); | |
1152 g_match_info_free(match_info); | |
1153 return; | |
1154 } | |
1155 | |
1156 user_name = g_match_info_fetch(match_info, 1); | |
1157 g_match_info_free(match_info); | |
1158 | |
1159 /* insert icon */ | |
1160 imhtml = GTK_IMHTML(PIDGIN_CONVERSATION(conv)->imhtml); | |
1161 text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imhtml)); | |
1162 | |
1163 /* get GtkTextIter in the target line */ | |
1164 linenumber = GPOINTER_TO_INT(g_hash_table_lookup(conv_hash, conv)); | |
1165 gtk_text_buffer_get_iter_at_line(text_buffer, | |
1166 &insertion_point, | |
1167 linenumber); | |
1168 | |
1169 switch(service) { | |
1170 case twitter_service: | |
1171 hash = icon_hash[twitter_service]; | |
1172 break; | |
1173 case wassr_service: | |
1174 hash = icon_hash[wassr_service]; | |
1175 break; | |
1176 case identica_service: | |
1177 hash = icon_hash[identica_service]; | |
1178 break; | |
1179 case jisko_service: | |
1180 hash = icon_hash[jisko_service]; | |
1181 break; | |
1182 default: | |
1183 twitter_debug("unknown service\n"); | |
1184 break; | |
1185 } | |
1186 | |
1187 if(hash) | |
1188 data = g_hash_table_lookup(hash, user_name); | |
1189 | |
1190 if(data) { | |
1191 /* check validity of icon */ | |
1192 int count_thres = purple_prefs_get_int(OPT_ICON_MAX_COUNT); | |
1193 int days_thres = DAYS_TO_SECONDS( | |
1194 purple_prefs_get_int(OPT_ICON_MAX_DAYS)); | |
1195 | |
1196 if(data->use_count > count_thres || | |
1197 (data->mtime && ((time(NULL) - data->mtime)) > days_thres)) { | |
1198 twitter_debug("count=%d mtime=%d\n", | |
1199 data->use_count, (int)(data->mtime)); | |
1200 renew = TRUE; | |
1201 request_icon(user_name, service, renew); | |
1202 } | |
1203 } | |
1204 | |
1205 /* if we don't have the icon for this user, put a mark instead and | |
1206 * request the icon */ | |
1207 if(!data || !data->pixbuf) { | |
1208 twitter_debug("%s's icon is not in memory.\n", user_name); | |
1209 mark_icon_for_user(gtk_text_buffer_create_mark( | |
1210 text_buffer, NULL, &insertion_point, FALSE), | |
1211 user_name, service); | |
1212 /* request to attach icon to the buffer */ | |
1213 request_icon(user_name, service, renew); | |
1214 g_free(user_name); user_name = NULL; | |
1215 return; | |
1216 } | |
1217 | |
1218 /* if we have icon for this user, insert icon immediately */ | |
1219 if(purple_prefs_get_bool(OPT_SHOW_ICON)) { | |
1220 gtk_text_buffer_insert_pixbuf(text_buffer, | |
1221 &insertion_point, | |
1222 data->pixbuf); | |
1223 data->use_count++; | |
1224 } | |
1225 g_free(user_name); user_name = NULL; | |
1226 | |
1227 twitter_debug("reach end of function\n"); | |
1228 } | |
1229 | |
1230 static gboolean | |
1231 load_plugin(PurplePlugin *plugin) | |
1232 { | |
1233 int i; | |
1234 | |
1235 /* connect to signal */ | |
1236 purple_signal_connect(purple_conversations_get_handle(), "writing-im-msg", | |
1237 plugin, PURPLE_CALLBACK(writing_im_cb), NULL); | |
1238 purple_signal_connect(purple_conversations_get_handle(), "sending-im-msg", | |
1239 plugin, PURPLE_CALLBACK(sending_im_cb), NULL); | |
1240 purple_signal_connect(purple_conversations_get_handle(), | |
1241 "conversation-created", | |
1242 plugin, PURPLE_CALLBACK(conv_created_cb), NULL); | |
1243 purple_signal_connect(purple_conversations_get_handle(), "receiving-im-msg", | |
1244 plugin, PURPLE_CALLBACK(receiving_im_cb), NULL); | |
1245 purple_signal_connect(pidgin_conversations_get_handle(), "displaying-im-msg", | |
1246 plugin, PURPLE_CALLBACK(displaying_im_cb), NULL); | |
1247 | |
1248 purple_signal_connect(pidgin_conversations_get_handle(), "displayed-im-msg", | |
1249 plugin, PURPLE_CALLBACK(displayed_im_cb), NULL); | |
1250 purple_signal_connect(purple_conversations_get_handle(), | |
1251 "deleting-conversation", | |
1252 plugin, PURPLE_CALLBACK(deleting_conv_cb), NULL); | |
1253 purple_signal_connect(purple_connections_get_handle(), "signed-on", | |
1254 plugin, PURPLE_CALLBACK(signed_on_cb), NULL); | |
1255 | |
1256 | |
1257 /* compile regex */ | |
1258 regp[RECIPIENT] = g_regex_new(P_RECIPIENT, 0, 0, NULL); | |
1259 regp[SENDER] = g_regex_new(P_SENDER, 0, 0, NULL); | |
1260 regp[COMMAND] = g_regex_new(P_COMMAND, G_REGEX_RAW, 0, NULL); | |
1261 regp[PSEUDO] = g_regex_new(P_PSEUDO, G_REGEX_RAW, 0, NULL); | |
1262 regp[USER] = g_regex_new(P_USER, 0, 0, NULL); | |
1263 regp[CHANNEL_WASSR] = g_regex_new(P_CHANNEL, 0, 0, NULL); | |
1264 regp[TAG_IDENTICA] = g_regex_new(P_TAG_IDENTICA, 0, 0, NULL); | |
1265 regp[IMAGE_TWITTER] = g_regex_new(P_IMAGE_TWITTER, 0, 0, NULL); | |
1266 regp[IMAGE_WASSR] = g_regex_new(P_IMAGE_WASSR, 0, 0, NULL); | |
1267 regp[IMAGE_IDENTICA] = g_regex_new(P_IMAGE_IDENTICA, 0, 0, NULL); | |
1268 regp[IMAGE_JISKO] = g_regex_new(P_IMAGE_JISKO, 0, 0, NULL); | |
1269 regp[SIZE_128_WASSR] = g_regex_new(P_SIZE_128_WASSR, 0, 0, NULL); | |
1270 regp[EXCESS_LF] = g_regex_new(P_EXCESS_LF, 0, 0, NULL); | |
1271 | |
1272 for(i = twitter_service; i < NUM_SERVICES; i++) { | |
1273 icon_hash[i] = g_hash_table_new_full(g_str_hash, g_str_equal, | |
1274 g_free, NULL); | |
1275 } | |
1276 | |
1277 conv_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, | |
1278 NULL, NULL); | |
1279 | |
1280 | |
1281 /* attach counter to the existing twitter window */ | |
1282 if(purple_prefs_get_bool(OPT_COUNTER)) { | |
1283 attach_to_window(); | |
1284 } | |
1285 | |
1286 return TRUE; | |
1287 } | |
1288 | |
1289 static void | |
1290 cancel_fetch_func(gpointer key, gpointer value, gpointer user_data) | |
1291 { | |
1292 icon_data *data = (icon_data *)value; | |
1293 | |
1294 if(!data) | |
1295 return; | |
1296 | |
1297 if(data->requested) { | |
1298 purple_util_fetch_url_cancel(data->fetch_data); | |
1299 data->fetch_data = NULL; | |
1300 data->requested = FALSE; | |
1301 } | |
1302 | |
1303 if(data->request_list) { | |
1304 twitter_debug("somehow, request_list != NULL\n"); | |
1305 } | |
1306 } | |
1307 | |
1308 static void | |
1309 cleanup_hash_entry_func(gpointer key, gpointer value, gpointer user_data) | |
1310 { | |
1311 remove_marks_func(key, value, user_data); | |
1312 cancel_fetch_func(key, value, user_data); | |
1313 } | |
1314 | |
1315 static gboolean | |
1316 unload_plugin(PurplePlugin *plugin) | |
1317 { | |
1318 int i; | |
1319 GList *current; | |
1320 | |
1321 twitter_debug("called\n"); | |
1322 | |
1323 /* disconnect from signal */ | |
1324 purple_signal_disconnect(purple_conversations_get_handle(), | |
1325 "writing-im-msg", | |
1326 plugin, PURPLE_CALLBACK(writing_im_cb)); | |
1327 purple_signal_disconnect(purple_conversations_get_handle(), | |
1328 "sending-im-msg", | |
1329 plugin, PURPLE_CALLBACK(sending_im_cb)); | |
1330 purple_signal_disconnect(purple_conversations_get_handle(), | |
1331 "conversation-created", | |
1332 plugin, PURPLE_CALLBACK(conv_created_cb)); | |
1333 purple_signal_disconnect(pidgin_conversations_get_handle(), | |
1334 "displaying-im-msg", | |
1335 plugin, PURPLE_CALLBACK(displaying_im_cb)); | |
1336 purple_signal_disconnect(pidgin_conversations_get_handle(), | |
1337 "displayed-im-msg", | |
1338 plugin, PURPLE_CALLBACK(displayed_im_cb)); | |
1339 purple_signal_disconnect(purple_conversations_get_handle(), | |
1340 "receiving-im-msg", | |
1341 plugin, PURPLE_CALLBACK(receiving_im_cb)); | |
1342 purple_signal_disconnect(purple_conversations_get_handle(), | |
1343 "deleting-conversation", | |
1344 plugin, PURPLE_CALLBACK(deleting_conv_cb)); | |
1345 purple_signal_disconnect(purple_connections_get_handle(), | |
1346 "signed-on", | |
1347 plugin, PURPLE_CALLBACK(signed_on_cb)); | |
1348 | |
1349 /* unreference regp */ | |
1350 for(i = 0; i < NUM_REGPS; i++) { | |
1351 g_regex_unref(regp[i]); | |
1352 } | |
1353 | |
1354 /* remove mark list in each hash entry */ | |
1355 /* cancel request that has not been finished yet */ | |
1356 for(i = twitter_service; i < NUM_SERVICES; i++) { | |
1357 /* delete mark list and stop requeset for each hash table */ | |
1358 g_hash_table_foreach(icon_hash[i], | |
1359 (GHFunc)cleanup_hash_entry_func, NULL); | |
1360 /* destroy hash table for icon_data */ | |
1361 g_hash_table_destroy(icon_hash[i]); | |
1362 } | |
1363 | |
1364 g_hash_table_destroy(conv_hash); | |
1365 | |
1366 /* detach from twitter window */ | |
1367 detach_from_window(); | |
1368 | |
1369 /* free wassr_parrot_list */ | |
1370 current = g_list_first(wassr_parrot_list); | |
1371 while(current) { | |
1372 GList *next; | |
1373 | |
1374 next = g_list_next(current); | |
1375 g_free(current->data); | |
1376 wassr_parrot_list = | |
1377 g_list_delete_link(wassr_parrot_list, current); | |
1378 | |
1379 current = next; | |
1380 } | |
1381 g_list_free(wassr_parrot_list); | |
1382 wassr_parrot_list = NULL; | |
1383 | |
1384 /* free identica_parot_list */ | |
1385 current = g_list_first(identica_parrot_list); | |
1386 while(current) { | |
1387 GList *next; | |
1388 | |
1389 next = g_list_next(current); | |
1390 g_free(current->data); | |
1391 identica_parrot_list = | |
1392 g_list_delete_link(identica_parrot_list, current); | |
1393 | |
1394 current = next; | |
1395 } | |
1396 g_list_free(identica_parrot_list); | |
1397 identica_parrot_list = NULL; | |
1398 | |
1399 return TRUE; | |
1400 } | |
1401 | |
1402 static PidginPluginUiInfo ui_info = { | |
1403 prefs_get_frame, | |
1404 0, /* page number - reserved */ | |
1405 NULL, /* reserved 1 */ | |
1406 NULL, /* reserved 2 */ | |
1407 NULL, /* reserved 3 */ | |
1408 NULL /* reserved 4 */ | |
1409 }; | |
1410 | |
1411 static PurplePluginInfo info = { | |
1412 PURPLE_PLUGIN_MAGIC, | |
1413 PURPLE_MAJOR_VERSION, | |
1414 PURPLE_MINOR_VERSION, | |
1415 PURPLE_PLUGIN_STANDARD, /**< type */ | |
1416 PIDGIN_PLUGIN_TYPE, /**< ui_req */ | |
1417 0, /**< flags */ | |
1418 NULL, /**< deps */ | |
1419 PURPLE_PRIORITY_DEFAULT, /**< priority */ | |
1420 PLUGIN_ID, /**< id */ | |
1421 "Pidgin-Twitter", /**< name */ | |
1422 "0.9.0d1", /**< version */ | |
1423 "provides useful features for twitter", /** summary */ | |
1424 "provides useful features for twitter", /** desc */ | |
1425 "Yoshiki Yazawa, mikanbako, \nKonosuke Watanabe, IWATA Ray, \nmojin, umq, \nthe pidging-twitter team", /**< author */ | |
1426 "http://www.honeyplanet.jp/pidgin-twitter/", /**< homepage */ | |
1427 load_plugin, /**< load */ | |
1428 unload_plugin, /**< unload */ | |
1429 NULL, /**< destroy */ | |
1430 &ui_info, /**< ui_info */ | |
1431 NULL, /**< extra_info */ | |
1432 NULL, /**< pref info */ | |
1433 NULL | |
1434 }; | |
1435 | |
1436 static void | |
1437 init_plugin(PurplePlugin *plugin) | |
1438 { | |
1439 char *dirname = NULL; | |
1440 | |
1441 g_type_init(); | |
1442 dirname = g_build_filename(purple_user_dir(), "pidgin-twitter", "icons", NULL); | |
1443 if(dirname) | |
1444 purple_prefs_add_string(OPT_ICON_DIR, dirname); | |
1445 g_free(dirname); | |
1446 | |
1447 /* add plugin preferences */ | |
1448 purple_prefs_add_none(OPT_PIDGINTWITTER); | |
1449 purple_prefs_add_bool(OPT_TRANSLATE_RECIPIENT, TRUE); | |
1450 purple_prefs_add_bool(OPT_TRANSLATE_SENDER, TRUE); | |
1451 purple_prefs_add_bool(OPT_TRANSLATE_CHANNEL, TRUE); | |
1452 purple_prefs_add_bool(OPT_ESCAPE_PSEUDO, TRUE); | |
1453 purple_prefs_add_bool(OPT_STRIP_EXCESS_LF, TRUE); | |
1454 | |
1455 purple_prefs_add_bool(OPT_PLAYSOUND_RECIPIENT, TRUE); | |
1456 purple_prefs_add_bool(OPT_PLAYSOUND_SENDER, TRUE); | |
1457 purple_prefs_add_int(OPT_SOUNDID_RECIPIENT, PURPLE_SOUND_POUNCE_DEFAULT); | |
1458 purple_prefs_add_string(OPT_USERLIST_RECIPIENT, DEFAULT_LIST); | |
1459 purple_prefs_add_int(OPT_SOUNDID_SENDER, PURPLE_SOUND_POUNCE_DEFAULT); | |
1460 purple_prefs_add_string(OPT_USERLIST_SENDER, DEFAULT_LIST); | |
1461 | |
1462 purple_prefs_add_bool(OPT_COUNTER, TRUE); | |
1463 purple_prefs_add_bool(OPT_SUPPRESS_OOPS, TRUE); | |
1464 purple_prefs_add_bool(OPT_PREVENT_NOTIFICATION, FALSE); | |
1465 | |
1466 purple_prefs_add_bool(OPT_API_BASE_POST, FALSE); | |
1467 purple_prefs_add_int(OPT_API_BASE_GET_INTERVAL, TWITTER_DEFAULT_INTERVAL); | |
1468 purple_prefs_add_string(OPT_SCREEN_NAME_TWITTER, EMPTY); | |
1469 purple_prefs_add_string(OPT_PASSWORD_TWITTER, EMPTY); | |
1470 purple_prefs_add_string(OPT_SCREEN_NAME_WASSR, EMPTY); | |
1471 purple_prefs_add_string(OPT_SCREEN_NAME_IDENTICA, EMPTY); | |
1472 purple_prefs_add_string(OPT_SCREEN_NAME_JISKO, EMPTY); | |
1473 | |
1474 purple_prefs_add_bool(OPT_SHOW_ICON, TRUE); | |
1475 purple_prefs_add_int(OPT_ICON_SIZE, DEFAULT_ICON_SIZE); | |
1476 purple_prefs_add_bool(OPT_UPDATE_ICON, TRUE); | |
1477 purple_prefs_add_int(OPT_ICON_MAX_COUNT, DEFAULT_ICON_MAX_COUNT); | |
1478 purple_prefs_add_int(OPT_ICON_MAX_DAYS, DEFAULT_ICON_MAX_DAYS); | |
1479 purple_prefs_add_bool(OPT_LOG_OUTPUT, FALSE); | |
1480 | |
1481 purple_prefs_add_bool(OPT_FILTER, TRUE); | |
1482 purple_prefs_add_bool(OPT_FILTER_EXCLUDE_REPLY, TRUE); | |
1483 purple_prefs_add_string(OPT_FILTER_TWITTER, DEFAULT_LIST); | |
1484 purple_prefs_add_string(OPT_FILTER_WASSR, DEFAULT_LIST); | |
1485 purple_prefs_add_string(OPT_FILTER_IDENTICA, DEFAULT_LIST); | |
1486 purple_prefs_add_string(OPT_FILTER_JISKO, DEFAULT_LIST); | |
1487 } | |
1488 | |
1489 PURPLE_INIT_PLUGIN(pidgin_twitter, init_plugin, info) |