| 1 /** |
|
| 2 * Copyright (C) 2009 Richard Nelson <wabz@whatsbeef.net> |
|
| 3 * |
|
| 4 * This program is free software; you can redistribute it and/or modify |
|
| 5 * it under the terms of the GNU General Public License as published by |
|
| 6 * the Free Software Foundation; either version 2 of the License, or |
|
| 7 * (at your option) any later version. |
|
| 8 * |
|
| 9 * This program is distributed in the hope that it will be useful, |
|
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 * GNU 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
|
| 17 */ |
|
| 18 |
|
| 19 #include <glib/gi18n-lib.h> |
|
| 20 |
|
| 21 #include <glib.h> |
|
| 22 #include <libsoup/soup.h> |
|
| 23 |
|
| 24 #define PREFS_SCHEMA "im.pidgin.Finch.plugin.TinyURL" |
|
| 25 #define PREF_LENGTH "length" |
|
| 26 #define PREF_URL "url" |
|
| 27 |
|
| 28 #include <purple.h> |
|
| 29 |
|
| 30 #include <gnt.h> |
|
| 31 |
|
| 32 #include <finch.h> |
|
| 33 |
|
| 34 |
|
| 35 static int tag_num = 0; |
|
| 36 static SoupSession *session = NULL; |
|
| 37 static GHashTable *tinyurl_cache = NULL; |
|
| 38 |
|
| 39 typedef struct { |
|
| 40 SoupMessage *msg; |
|
| 41 gchar *original_url; |
|
| 42 PurpleConversation *conv; |
|
| 43 gchar *tag; |
|
| 44 int num; |
|
| 45 } CbInfo; |
|
| 46 |
|
| 47 static void process_urls(PurpleConversation *conv, GList *urls); |
|
| 48 |
|
| 49 /* 3 functions from util.c */ |
|
| 50 static gboolean |
|
| 51 badchar(char c) |
|
| 52 { |
|
| 53 switch (c) { |
|
| 54 case ' ': |
|
| 55 case ',': |
|
| 56 case '\0': |
|
| 57 case '\n': |
|
| 58 case '\r': |
|
| 59 case '<': |
|
| 60 case '>': |
|
| 61 case '"': |
|
| 62 case '\'': |
|
| 63 return TRUE; |
|
| 64 default: |
|
| 65 return FALSE; |
|
| 66 } |
|
| 67 } |
|
| 68 |
|
| 69 static gboolean |
|
| 70 badentity(const char *c) |
|
| 71 { |
|
| 72 if (!g_ascii_strncasecmp(c, "<", 4) || |
|
| 73 !g_ascii_strncasecmp(c, ">", 4) || |
|
| 74 !g_ascii_strncasecmp(c, """, 6)) { |
|
| 75 return TRUE; |
|
| 76 } |
|
| 77 return FALSE; |
|
| 78 } |
|
| 79 |
|
| 80 static GList *extract_urls(const char *text) |
|
| 81 { |
|
| 82 const char *t, *c, *q = NULL; |
|
| 83 char *url_buf; |
|
| 84 GList *ret = NULL; |
|
| 85 gboolean inside_html = FALSE; |
|
| 86 int inside_paren = 0; |
|
| 87 c = text; |
|
| 88 while (*c) { |
|
| 89 if (*c == '(' && !inside_html) { |
|
| 90 inside_paren++; |
|
| 91 c++; |
|
| 92 } |
|
| 93 if (inside_html) { |
|
| 94 if (*c == '>') { |
|
| 95 inside_html = FALSE; |
|
| 96 } else if (!q && (*c == '\"' || *c == '\'')) { |
|
| 97 q = c; |
|
| 98 } else if(q) { |
|
| 99 if(*c == *q) |
|
| 100 q = NULL; |
|
| 101 } |
|
| 102 } else if (*c == '<') { |
|
| 103 inside_html = TRUE; |
|
| 104 if (!g_ascii_strncasecmp(c, "<A", 2)) { |
|
| 105 while (1) { |
|
| 106 if (*c == '>') { |
|
| 107 inside_html = FALSE; |
|
| 108 break; |
|
| 109 } |
|
| 110 c++; |
|
| 111 if (!(*c)) |
|
| 112 break; |
|
| 113 } |
|
| 114 } |
|
| 115 } else if ((*c=='h') && (!g_ascii_strncasecmp(c, "http://", 7) || |
|
| 116 (!g_ascii_strncasecmp(c, "https://", 8)))) { |
|
| 117 t = c; |
|
| 118 while (1) { |
|
| 119 if (badchar(*t) || badentity(t)) { |
|
| 120 |
|
| 121 if ((!g_ascii_strncasecmp(c, "http://", 7) && (t - c == 7)) || |
|
| 122 (!g_ascii_strncasecmp(c, "https://", 8) && (t - c == 8))) { |
|
| 123 break; |
|
| 124 } |
|
| 125 |
|
| 126 if (*(t) == ',' && (*(t + 1) != ' ')) { |
|
| 127 t++; |
|
| 128 continue; |
|
| 129 } |
|
| 130 |
|
| 131 if (*(t - 1) == '.') |
|
| 132 t--; |
|
| 133 if ((*(t - 1) == ')' && (inside_paren > 0))) { |
|
| 134 t--; |
|
| 135 } |
|
| 136 |
|
| 137 url_buf = g_strndup(c, t - c); |
|
| 138 if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) { |
|
| 139 purple_debug_info("TinyURL", "Added URL %s\n", url_buf); |
|
| 140 ret = g_list_append(ret, url_buf); |
|
| 141 } else { |
|
| 142 g_free(url_buf); |
|
| 143 } |
|
| 144 c = t; |
|
| 145 break; |
|
| 146 } |
|
| 147 t++; |
|
| 148 |
|
| 149 } |
|
| 150 } else if (!g_ascii_strncasecmp(c, "www.", 4) && (c == text || badchar(c[-1]) || badentity(c-1))) { |
|
| 151 if (c[4] != '.') { |
|
| 152 t = c; |
|
| 153 while (1) { |
|
| 154 if (badchar(*t) || badentity(t)) { |
|
| 155 if (t - c == 4) { |
|
| 156 break; |
|
| 157 } |
|
| 158 |
|
| 159 if (*(t) == ',' && (*(t + 1) != ' ')) { |
|
| 160 t++; |
|
| 161 continue; |
|
| 162 } |
|
| 163 |
|
| 164 if (*(t - 1) == '.') |
|
| 165 t--; |
|
| 166 if ((*(t - 1) == ')' && (inside_paren > 0))) { |
|
| 167 t--; |
|
| 168 } |
|
| 169 url_buf = g_strndup(c, t - c); |
|
| 170 if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) { |
|
| 171 purple_debug_info("TinyURL", "Added URL %s\n", url_buf); |
|
| 172 ret = g_list_append(ret, url_buf); |
|
| 173 } else { |
|
| 174 g_free(url_buf); |
|
| 175 } |
|
| 176 c = t; |
|
| 177 break; |
|
| 178 } |
|
| 179 t++; |
|
| 180 } |
|
| 181 } |
|
| 182 } |
|
| 183 if (*c == ')' && !inside_html) { |
|
| 184 inside_paren--; |
|
| 185 c++; |
|
| 186 } |
|
| 187 if (*c == 0) |
|
| 188 break; |
|
| 189 c++; |
|
| 190 } |
|
| 191 return ret; |
|
| 192 } |
|
| 193 |
|
| 194 static void |
|
| 195 url_fetched(GObject *source, GAsyncResult *result, gpointer user_data) { |
|
| 196 CbInfo *data = (CbInfo *)user_data; |
|
| 197 PurpleConversation *conv = data->conv; |
|
| 198 PurpleConversationManager *manager; |
|
| 199 GList *convs; |
|
| 200 GBytes *response_body = NULL; |
|
| 201 const gchar *url; |
|
| 202 |
|
| 203 manager = purple_conversation_manager_get_default(); |
|
| 204 convs = purple_conversation_manager_get_all(manager); |
|
| 205 |
|
| 206 if(SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(data->msg))) { |
|
| 207 response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), |
|
| 208 result, NULL); |
|
| 209 } |
|
| 210 if (response_body != NULL) { |
|
| 211 gchar *tmp = NULL; |
|
| 212 gsize size = 0; |
|
| 213 |
|
| 214 /* Ensure URL is NUL-terminated. */ |
|
| 215 url = g_bytes_get_data(response_body, &size); |
|
| 216 tmp = g_strndup(url, size); |
|
| 217 url = tmp; |
|
| 218 |
|
| 219 g_hash_table_insert(tinyurl_cache, data->original_url, tmp); |
|
| 220 g_bytes_unref(response_body); |
|
| 221 } else { |
|
| 222 url = _("Error while querying TinyURL"); |
|
| 223 g_free(data->original_url); |
|
| 224 } |
|
| 225 |
|
| 226 /* ensure the conversation still exists */ |
|
| 227 if (g_list_find(convs, conv)) { |
|
| 228 FinchConv *fconv = FINCH_CONV(conv); |
|
| 229 gchar *str = g_strdup_printf("[%d] %s", data->num, url); |
|
| 230 GntTextView *tv = GNT_TEXT_VIEW(fconv->tv); |
|
| 231 gnt_text_view_tag_change(tv, data->tag, str, FALSE); |
|
| 232 g_free(str); |
|
| 233 g_free(data->tag); |
|
| 234 g_object_unref(data->msg); |
|
| 235 g_free(data); |
|
| 236 return; |
|
| 237 } |
|
| 238 g_free(data->tag); |
|
| 239 g_object_unref(data->msg); |
|
| 240 g_free(data); |
|
| 241 purple_debug_info("TinyURL", "Conversation no longer exists... :(\n"); |
|
| 242 } |
|
| 243 |
|
| 244 static gboolean |
|
| 245 writing_msg(PurpleConversation *conv, PurpleMessage *msg, |
|
| 246 G_GNUC_UNUSED gpointer data) |
|
| 247 { |
|
| 248 GString *t; |
|
| 249 GList *iter, *urls, *next; |
|
| 250 int c = 0; |
|
| 251 GSettings *settings = NULL; |
|
| 252 gint min_url_length; |
|
| 253 |
|
| 254 if (purple_message_get_flags(msg) & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_INVISIBLE)) |
|
| 255 return FALSE; |
|
| 256 |
|
| 257 urls = g_object_get_data(G_OBJECT(conv), "TinyURLs"); |
|
| 258 g_list_free_full(urls, g_free); |
|
| 259 urls = extract_urls(purple_message_get_contents(msg)); |
|
| 260 if (!urls) |
|
| 261 return FALSE; |
|
| 262 |
|
| 263 settings = g_settings_new_with_backend(PREFS_SCHEMA, |
|
| 264 purple_core_get_settings_backend()); |
|
| 265 min_url_length = g_settings_get_int(settings, PREF_LENGTH); |
|
| 266 g_object_unref(settings); |
|
| 267 |
|
| 268 t = g_string_new(g_strdup(purple_message_get_contents(msg))); |
|
| 269 for (iter = urls; iter; iter = next) { |
|
| 270 next = iter->next; |
|
| 271 if (g_utf8_strlen((char *)iter->data, -1) >= min_url_length) { |
|
| 272 int pos, x = 0; |
|
| 273 gchar *j, *s, *str, *orig; |
|
| 274 glong len = g_utf8_strlen(iter->data, -1); |
|
| 275 s = g_strdup(t->str); |
|
| 276 orig = s; |
|
| 277 str = g_strdup_printf("[%d]", ++c); |
|
| 278 while ((j = strstr(s, iter->data))) { /* replace all occurrences */ |
|
| 279 pos = j - orig + (x++ * 3); |
|
| 280 s = j + len; |
|
| 281 t = g_string_insert(t, pos + len, str); |
|
| 282 if (*s == '\0') break; |
|
| 283 } |
|
| 284 g_free(orig); |
|
| 285 g_free(str); |
|
| 286 continue; |
|
| 287 } else { |
|
| 288 g_free(iter->data); |
|
| 289 urls = g_list_delete_link(urls, iter); |
|
| 290 } |
|
| 291 } |
|
| 292 purple_message_set_contents(msg, t->str); |
|
| 293 g_string_free(t, TRUE); |
|
| 294 if (conv != NULL) |
|
| 295 g_object_set_data(G_OBJECT(conv), "TinyURLs", urls); |
|
| 296 return FALSE; |
|
| 297 } |
|
| 298 |
|
| 299 static void |
|
| 300 wrote_msg(PurpleConversation *conv, PurpleMessage *pmsg, |
|
| 301 G_GNUC_UNUSED gpointer _unused) |
|
| 302 { |
|
| 303 GList *urls; |
|
| 304 |
|
| 305 if (purple_message_get_flags(pmsg) & PURPLE_MESSAGE_SEND) |
|
| 306 return; |
|
| 307 |
|
| 308 urls = g_object_get_data(G_OBJECT(conv), "TinyURLs"); |
|
| 309 if (urls == NULL) |
|
| 310 return; |
|
| 311 |
|
| 312 process_urls(conv, urls); |
|
| 313 g_object_set_data(G_OBJECT(conv), "TinyURLs", NULL); |
|
| 314 } |
|
| 315 |
|
| 316 /* Frees 'urls' */ |
|
| 317 static void |
|
| 318 process_urls(PurpleConversation *conv, GList *urls) |
|
| 319 { |
|
| 320 GList *iter; |
|
| 321 int c; |
|
| 322 FinchConv *fconv = FINCH_CONV(conv); |
|
| 323 GntTextView *tv = GNT_TEXT_VIEW(fconv->tv); |
|
| 324 GSettings *settings = NULL; |
|
| 325 gchar *tinyurl_prefix = NULL; |
|
| 326 |
|
| 327 settings = g_settings_new_with_backend(PREFS_SCHEMA, |
|
| 328 purple_core_get_settings_backend()); |
|
| 329 tinyurl_prefix = g_settings_get_string(settings, PREF_URL); |
|
| 330 g_object_unref(settings); |
|
| 331 |
|
| 332 for (iter = urls, c = 1; iter; iter = iter->next, c++) { |
|
| 333 int i; |
|
| 334 SoupMessage *msg; |
|
| 335 CbInfo *cbdata; |
|
| 336 gchar *url; |
|
| 337 gchar *original_url; |
|
| 338 const gchar *tiny_url; |
|
| 339 |
|
| 340 i = gnt_text_view_get_lines_below(tv); |
|
| 341 |
|
| 342 original_url = purple_unescape_html((char *)iter->data); |
|
| 343 tiny_url = g_hash_table_lookup(tinyurl_cache, original_url); |
|
| 344 if (tiny_url) { |
|
| 345 gchar *str = g_strdup_printf("\n[%d] %s", c, tiny_url); |
|
| 346 |
|
| 347 g_free(original_url); |
|
| 348 gnt_text_view_append_text_with_flags(tv, str, GNT_TEXT_FLAG_DIM); |
|
| 349 if (i == 0) |
|
| 350 gnt_text_view_scroll(tv, 0); |
|
| 351 g_free(str); |
|
| 352 continue; |
|
| 353 } |
|
| 354 cbdata = g_new(CbInfo, 1); |
|
| 355 cbdata->num = c; |
|
| 356 cbdata->original_url = original_url; |
|
| 357 cbdata->tag = g_strdup_printf("%s%d", "tiny_", tag_num++); |
|
| 358 cbdata->conv = conv; |
|
| 359 if (g_ascii_strncasecmp(original_url, "http://", 7) && g_ascii_strncasecmp(original_url, "https://", 8)) { |
|
| 360 url = g_strdup_printf("%shttp%%3A%%2F%%2F%s", tinyurl_prefix, |
|
| 361 purple_url_encode(original_url)); |
|
| 362 } else { |
|
| 363 url = g_strdup_printf("%s%s", tinyurl_prefix, |
|
| 364 purple_url_encode(original_url)); |
|
| 365 } |
|
| 366 cbdata->msg = msg = soup_message_new("GET", url); |
|
| 367 soup_session_send_and_read_async(session, msg, G_PRIORITY_DEFAULT, |
|
| 368 NULL, url_fetched, cbdata); |
|
| 369 gnt_text_view_append_text_with_tag((tv), _("\nFetching TinyURL..."), |
|
| 370 GNT_TEXT_FLAG_DIM, cbdata->tag); |
|
| 371 if (i == 0) |
|
| 372 gnt_text_view_scroll(tv, 0); |
|
| 373 g_free(iter->data); |
|
| 374 g_free(url); |
|
| 375 } |
|
| 376 g_list_free(urls); |
|
| 377 g_free(tinyurl_prefix); |
|
| 378 } |
|
| 379 |
|
| 380 static void |
|
| 381 free_conv_urls(PurpleConversation *conv) |
|
| 382 { |
|
| 383 GList *urls = g_object_get_data(G_OBJECT(conv), "TinyURLs"); |
|
| 384 g_list_free_full(urls, g_free); |
|
| 385 } |
|
| 386 |
|
| 387 static void |
|
| 388 tinyurl_notify_tinyuri(GntWidget *win, const gchar *url) |
|
| 389 { |
|
| 390 gchar *message; |
|
| 391 GntWidget *label = g_object_get_data(G_OBJECT(win), "info-widget"); |
|
| 392 |
|
| 393 message = g_strdup_printf(_("TinyURL for above: %s"), url); |
|
| 394 gnt_label_set_text(GNT_LABEL(label), message); |
|
| 395 g_free(message); |
|
| 396 } |
|
| 397 |
|
| 398 static void |
|
| 399 tinyurl_notify_fetch_cb(GObject *source, GAsyncResult *result, gpointer data) |
|
| 400 { |
|
| 401 SoupMessage *msg = data; |
|
| 402 GntWidget *win = NULL; |
|
| 403 GBytes *response_body = NULL; |
|
| 404 const gchar *tmp = NULL; |
|
| 405 gsize size = 0; |
|
| 406 gchar *url = NULL; |
|
| 407 const gchar *original_url = NULL; |
|
| 408 |
|
| 409 if(SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(msg))) { |
|
| 410 response_body = soup_session_send_and_read_finish(SOUP_SESSION(source), |
|
| 411 result, NULL); |
|
| 412 } |
|
| 413 |
|
| 414 if (response_body == NULL) { |
|
| 415 g_object_unref(msg); |
|
| 416 return; |
|
| 417 } |
|
| 418 |
|
| 419 win = g_object_get_data(G_OBJECT(msg), "gnttinyurl-window"); |
|
| 420 original_url = g_object_get_data(G_OBJECT(msg), "gnttinyurl-original"); |
|
| 421 tmp = g_bytes_get_data(response_body, &size); |
|
| 422 url = g_strndup(tmp, size); |
|
| 423 g_hash_table_insert(tinyurl_cache, g_strdup(original_url), url); |
|
| 424 |
|
| 425 tinyurl_notify_tinyuri(win, url); |
|
| 426 |
|
| 427 g_bytes_unref(response_body); |
|
| 428 g_object_unref(msg); |
|
| 429 } |
|
| 430 |
|
| 431 static void * |
|
| 432 tinyurl_notify_uri(const char *uri) |
|
| 433 { |
|
| 434 char *fullurl = NULL; |
|
| 435 GntWidget *win; |
|
| 436 GCancellable *cancellable = NULL; |
|
| 437 SoupMessage *msg; |
|
| 438 const gchar *tiny_url; |
|
| 439 GSettings *settings = NULL; |
|
| 440 gchar *tinyurl_prefix = NULL; |
|
| 441 |
|
| 442 /* XXX: The following expects that finch_notify_message gets called. This |
|
| 443 * may not always happen, e.g. when another plugin sets its own |
|
| 444 * notify_message. So tread carefully. */ |
|
| 445 win = purple_notify_message(NULL, PURPLE_NOTIFY_MSG_INFO, _("URI"), uri, |
|
| 446 _("Please wait while TinyURL fetches a shorter URL ..."), NULL, NULL, NULL); |
|
| 447 if (!GNT_IS_WINDOW(win) || !g_object_get_data(G_OBJECT(win), "info-widget")) |
|
| 448 return win; |
|
| 449 |
|
| 450 tiny_url = g_hash_table_lookup(tinyurl_cache, uri); |
|
| 451 if (tiny_url) { |
|
| 452 tinyurl_notify_tinyuri(win, tiny_url); |
|
| 453 return win; |
|
| 454 } |
|
| 455 |
|
| 456 settings = g_settings_new_with_backend(PREFS_SCHEMA, |
|
| 457 purple_core_get_settings_backend()); |
|
| 458 tinyurl_prefix = g_settings_get_string(settings, PREF_URL); |
|
| 459 g_object_unref(settings); |
|
| 460 |
|
| 461 if (g_ascii_strncasecmp(uri, "http://", 7) && g_ascii_strncasecmp(uri, "https://", 8)) { |
|
| 462 fullurl = g_strdup_printf("%shttp%%3A%%2F%%2F%s", tinyurl_prefix, |
|
| 463 purple_url_encode(uri)); |
|
| 464 } else { |
|
| 465 fullurl = g_strdup_printf("%s%s", tinyurl_prefix, |
|
| 466 purple_url_encode(uri)); |
|
| 467 } |
|
| 468 |
|
| 469 g_free(tinyurl_prefix); |
|
| 470 |
|
| 471 /* Make a cancellable and cancel it when the window is destroyed, so that |
|
| 472 * the callback does not try to use a non-existent window. |
|
| 473 */ |
|
| 474 cancellable = g_cancellable_new(); |
|
| 475 msg = soup_message_new("GET", fullurl); |
|
| 476 g_object_set_data(G_OBJECT(msg), "gnttinyurl-window", win); |
|
| 477 g_object_set_data_full(G_OBJECT(msg), "gnttinyurl-original", g_strdup(uri), |
|
| 478 g_free); |
|
| 479 |
|
| 480 soup_session_send_and_read_async(session, msg, G_PRIORITY_DEFAULT, |
|
| 481 cancellable, tinyurl_notify_fetch_cb, msg); |
|
| 482 g_signal_connect_object(win, "destroy", G_CALLBACK(g_cancellable_cancel), |
|
| 483 cancellable, G_CONNECT_SWAPPED); |
|
| 484 g_free(fullurl); |
|
| 485 g_object_unref(cancellable); |
|
| 486 |
|
| 487 return win; |
|
| 488 } |
|
| 489 |
|
| 490 static GPluginPluginInfo * |
|
| 491 tiny_url_query(G_GNUC_UNUSED GError **error) { |
|
| 492 const gchar * const authors[] = { |
|
| 493 "Richard Nelson <wabz@whatsbeef.net>", |
|
| 494 NULL |
|
| 495 }; |
|
| 496 |
|
| 497 return finch_plugin_info_new( |
|
| 498 "id", "TinyURL", |
|
| 499 "name", N_("TinyURL"), |
|
| 500 "version", DISPLAY_VERSION, |
|
| 501 "category", N_("Utility"), |
|
| 502 "summary", N_("TinyURL plugin"), |
|
| 503 "description", N_("When receiving a message with URL(s), " |
|
| 504 "use TinyURL for easier copying"), |
|
| 505 "authors", authors, |
|
| 506 "website", PURPLE_WEBSITE, |
|
| 507 "abi-version", PURPLE_ABI_VERSION, |
|
| 508 "settings-schema", PREFS_SCHEMA, |
|
| 509 NULL |
|
| 510 ); |
|
| 511 } |
|
| 512 |
|
| 513 static gboolean |
|
| 514 tiny_url_load(GPluginPlugin *plugin, G_GNUC_UNUSED GError **error) { |
|
| 515 PurpleNotifyUiOps *ops = purple_notify_get_ui_ops(); |
|
| 516 |
|
| 517 session = soup_session_new(); |
|
| 518 |
|
| 519 g_object_set_data(G_OBJECT(plugin), "notify-uri", ops->notify_uri); |
|
| 520 ops->notify_uri = tinyurl_notify_uri; |
|
| 521 |
|
| 522 tinyurl_cache = g_hash_table_new_full(g_str_hash, g_str_equal, |
|
| 523 g_free, g_free); |
|
| 524 |
|
| 525 purple_signal_connect(purple_conversations_get_handle(), |
|
| 526 "wrote-im-msg", |
|
| 527 plugin, G_CALLBACK(wrote_msg), NULL); |
|
| 528 purple_signal_connect(purple_conversations_get_handle(), |
|
| 529 "wrote-chat-msg", |
|
| 530 plugin, G_CALLBACK(wrote_msg), NULL); |
|
| 531 purple_signal_connect(purple_conversations_get_handle(), |
|
| 532 "writing-im-msg", |
|
| 533 plugin, G_CALLBACK(writing_msg), NULL); |
|
| 534 purple_signal_connect(purple_conversations_get_handle(), |
|
| 535 "writing-chat-msg", |
|
| 536 plugin, G_CALLBACK(writing_msg), NULL); |
|
| 537 purple_signal_connect(purple_conversations_get_handle(), |
|
| 538 "deleting-conversation", |
|
| 539 plugin, G_CALLBACK(free_conv_urls), NULL); |
|
| 540 |
|
| 541 return TRUE; |
|
| 542 } |
|
| 543 |
|
| 544 static gboolean |
|
| 545 tiny_url_unload(GPluginPlugin *plugin, G_GNUC_UNUSED gboolean shutdown, |
|
| 546 G_GNUC_UNUSED GError **error) |
|
| 547 { |
|
| 548 PurpleNotifyUiOps *ops = purple_notify_get_ui_ops(); |
|
| 549 if (ops->notify_uri == tinyurl_notify_uri) |
|
| 550 ops->notify_uri = g_object_get_data(G_OBJECT(plugin), "notify-uri"); |
|
| 551 |
|
| 552 soup_session_abort(session); |
|
| 553 g_clear_object(&session); |
|
| 554 |
|
| 555 g_clear_pointer(&tinyurl_cache, g_hash_table_destroy); |
|
| 556 |
|
| 557 return TRUE; |
|
| 558 } |
|
| 559 |
|
| 560 GPLUGIN_NATIVE_PLUGIN_DECLARE(tiny_url) |
|