| 1 /* |
|
| 2 * finch |
|
| 3 * |
|
| 4 * Finch is the legal property of its developers, whose names are too numerous |
|
| 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
|
| 21 */ |
|
| 22 |
|
| 23 #include <glib/gi18n-lib.h> |
|
| 24 |
|
| 25 #include <purple.h> |
|
| 26 |
|
| 27 #include <gnt.h> |
|
| 28 |
|
| 29 #include "gntlog.h" |
|
| 30 |
|
| 31 static GHashTable *log_viewers = NULL; |
|
| 32 static void populate_log_tree(FinchLogViewer *lv); |
|
| 33 static FinchLogViewer *syslog_viewer = NULL; |
|
| 34 |
|
| 35 struct log_viewer_hash { |
|
| 36 PurpleLogType type; |
|
| 37 char *username; |
|
| 38 PurpleAccount *account; |
|
| 39 PurpleContact *contact; |
|
| 40 }; |
|
| 41 |
|
| 42 static guint log_viewer_hash(gconstpointer data) |
|
| 43 { |
|
| 44 const struct log_viewer_hash *viewer = data; |
|
| 45 |
|
| 46 if (viewer->contact != NULL) |
|
| 47 return g_direct_hash(viewer->contact); |
|
| 48 |
|
| 49 if (viewer->account) { |
|
| 50 return g_str_hash(viewer->username) + |
|
| 51 g_str_hash(purple_account_get_username(viewer->account)); |
|
| 52 } |
|
| 53 |
|
| 54 return g_direct_hash(viewer); |
|
| 55 } |
|
| 56 |
|
| 57 static gboolean log_viewer_equal(gconstpointer y, gconstpointer z) |
|
| 58 { |
|
| 59 const struct log_viewer_hash *a, *b; |
|
| 60 int ret; |
|
| 61 char *normal; |
|
| 62 |
|
| 63 a = y; |
|
| 64 b = z; |
|
| 65 |
|
| 66 if (a->contact != NULL) { |
|
| 67 if (b->contact != NULL) |
|
| 68 return (a->contact == b->contact); |
|
| 69 else |
|
| 70 return FALSE; |
|
| 71 } else { |
|
| 72 if (b->contact != NULL) |
|
| 73 return FALSE; |
|
| 74 } |
|
| 75 |
|
| 76 if (a->username && b->username) { |
|
| 77 normal = g_strdup(purple_normalize(a->account, a->username)); |
|
| 78 ret = (a->account == b->account) && |
|
| 79 purple_strequal(normal, purple_normalize(b->account, b->username)); |
|
| 80 g_free(normal); |
|
| 81 } else { |
|
| 82 ret = (a == b); |
|
| 83 } |
|
| 84 |
|
| 85 return ret; |
|
| 86 } |
|
| 87 |
|
| 88 static gchar *log_get_date(PurpleLog *log) |
|
| 89 { |
|
| 90 GDateTime *dt; |
|
| 91 gchar *ret; |
|
| 92 dt = g_date_time_to_local(log->time); |
|
| 93 ret = g_date_time_format(dt, "%c"); |
|
| 94 g_date_time_unref(dt); |
|
| 95 return ret; |
|
| 96 } |
|
| 97 |
|
| 98 static void search_cb(GntWidget *button, FinchLogViewer *lv) |
|
| 99 { |
|
| 100 const char *search_term = gnt_entry_get_text(GNT_ENTRY(lv->entry)); |
|
| 101 GList *logs; |
|
| 102 |
|
| 103 if (!(*search_term)) { |
|
| 104 /* reset the tree */ |
|
| 105 gnt_tree_remove_all(GNT_TREE(lv->tree)); |
|
| 106 g_free(lv->search); |
|
| 107 lv->search = NULL; |
|
| 108 populate_log_tree(lv); |
|
| 109 return; |
|
| 110 } |
|
| 111 |
|
| 112 if (lv->search != NULL && purple_strequal(lv->search, search_term)) { |
|
| 113 return; |
|
| 114 } |
|
| 115 |
|
| 116 g_free(lv->search); |
|
| 117 lv->search = g_strdup(search_term); |
|
| 118 |
|
| 119 gnt_tree_remove_all(GNT_TREE(lv->tree)); |
|
| 120 gnt_text_view_clear(GNT_TEXT_VIEW(lv->text)); |
|
| 121 |
|
| 122 for (logs = lv->logs; logs != NULL; logs = logs->next) { |
|
| 123 char *read = purple_log_read((PurpleLog*)logs->data, NULL); |
|
| 124 if (read && *read && purple_strcasestr(read, search_term)) { |
|
| 125 PurpleLog *log = logs->data; |
|
| 126 gchar *log_date = log_get_date(log); |
|
| 127 |
|
| 128 gnt_tree_add_row_last(GNT_TREE(lv->tree), |
|
| 129 log, |
|
| 130 gnt_tree_create_row(GNT_TREE(lv->tree), log_date), |
|
| 131 NULL); |
|
| 132 g_free(log_date); |
|
| 133 } |
|
| 134 g_free(read); |
|
| 135 } |
|
| 136 |
|
| 137 } |
|
| 138 |
|
| 139 static void |
|
| 140 destroy_cb(GntWidget *w, struct log_viewer_hash *ht) |
|
| 141 { |
|
| 142 FinchLogViewer *lv = syslog_viewer; |
|
| 143 |
|
| 144 if (ht != NULL) { |
|
| 145 lv = g_hash_table_lookup(log_viewers, ht); |
|
| 146 g_hash_table_remove(log_viewers, ht); |
|
| 147 |
|
| 148 g_free(ht->username); |
|
| 149 g_free(ht); |
|
| 150 } else |
|
| 151 syslog_viewer = NULL; |
|
| 152 |
|
| 153 purple_request_close_with_handle(lv); |
|
| 154 |
|
| 155 g_list_free_full(lv->logs, (GDestroyNotify)purple_log_free); |
|
| 156 |
|
| 157 g_free(lv->search); |
|
| 158 g_free(lv); |
|
| 159 |
|
| 160 gnt_widget_destroy(w); |
|
| 161 } |
|
| 162 |
|
| 163 static void log_select_cb(GntWidget *w, gpointer old, gpointer new, FinchLogViewer *viewer) |
|
| 164 { |
|
| 165 GntTree *tree = GNT_TREE(w); |
|
| 166 PurpleLog *log = NULL; |
|
| 167 PurpleLogReadFlags flags; |
|
| 168 char *read = NULL, *strip, *newline; |
|
| 169 |
|
| 170 if (!viewer->search && !gnt_tree_get_parent_key(tree, new)) |
|
| 171 return; |
|
| 172 |
|
| 173 log = (PurpleLog *)new; |
|
| 174 |
|
| 175 if (log == NULL) |
|
| 176 return; |
|
| 177 |
|
| 178 if (log->type != PURPLE_LOG_SYSTEM) { |
|
| 179 gchar *log_date = log_get_date(log); |
|
| 180 char *title; |
|
| 181 if (log->type == PURPLE_LOG_CHAT) |
|
| 182 title = g_strdup_printf(_("Conversation in %s on %s"), |
|
| 183 log->name, log_date); |
|
| 184 else |
|
| 185 title = g_strdup_printf(_("Conversation with %s on %s"), |
|
| 186 log->name, log_date); |
|
| 187 |
|
| 188 gnt_label_set_text(GNT_LABEL(viewer->label), title); |
|
| 189 g_free(log_date); |
|
| 190 g_free(title); |
|
| 191 } |
|
| 192 |
|
| 193 read = purple_log_read(log, &flags); |
|
| 194 if (flags != PURPLE_LOG_READ_NO_NEWLINE) { |
|
| 195 newline = purple_strdup_withhtml(read); |
|
| 196 strip = purple_markup_strip_html(newline); |
|
| 197 g_free(newline); |
|
| 198 } else { |
|
| 199 strip = purple_markup_strip_html(read); |
|
| 200 } |
|
| 201 viewer->flags = flags; |
|
| 202 |
|
| 203 purple_signal_emit(finch_log_get_handle(), "log-displaying", viewer, log); |
|
| 204 |
|
| 205 gnt_text_view_clear(GNT_TEXT_VIEW(viewer->text)); |
|
| 206 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(viewer->text), strip, GNT_TEXT_FLAG_NORMAL); |
|
| 207 g_free(read); |
|
| 208 g_free(strip); |
|
| 209 } |
|
| 210 |
|
| 211 /* I want to make this smarter, but haven't come up with a cool algorithm to do so, yet. |
|
| 212 * I want the tree to be divided into groups like "Today," "Yesterday," "Last week," |
|
| 213 * "August," "2002," etc. based on how many conversation took place in each subdivision. |
|
| 214 * |
|
| 215 * For now, I'll just make it a flat list. |
|
| 216 */ |
|
| 217 static void populate_log_tree(FinchLogViewer *lv) |
|
| 218 /* Logs are made from trees in real life. |
|
| 219 This is a tree made from logs */ |
|
| 220 { |
|
| 221 gchar *pmonth; |
|
| 222 gchar *month = NULL; |
|
| 223 char prev_top_month[30] = ""; |
|
| 224 GList *logs = lv->logs; |
|
| 225 |
|
| 226 while (logs != NULL) { |
|
| 227 PurpleLog *log = logs->data; |
|
| 228 GDateTime *dt; |
|
| 229 gchar *log_date; |
|
| 230 |
|
| 231 dt = g_date_time_to_local(log->time); |
|
| 232 pmonth = g_date_time_format(dt, _("%B %Y")); |
|
| 233 |
|
| 234 if (!purple_strequal(pmonth, prev_top_month)) { |
|
| 235 month = g_strdup(pmonth); |
|
| 236 /* top level */ |
|
| 237 gnt_tree_add_row_last(GNT_TREE(lv->tree), |
|
| 238 month, |
|
| 239 gnt_tree_create_row(GNT_TREE(lv->tree), month), |
|
| 240 NULL); |
|
| 241 gnt_tree_set_expanded(GNT_TREE(lv->tree), month, FALSE); |
|
| 242 |
|
| 243 g_strlcpy(prev_top_month, month, sizeof(prev_top_month)); |
|
| 244 } |
|
| 245 |
|
| 246 /* sub */ |
|
| 247 log_date = g_date_time_format(dt, "%c"); |
|
| 248 gnt_tree_add_row_last(GNT_TREE(lv->tree), |
|
| 249 log, |
|
| 250 gnt_tree_create_row(GNT_TREE(lv->tree), log_date), |
|
| 251 month); |
|
| 252 |
|
| 253 g_free(log_date); |
|
| 254 g_free(pmonth); |
|
| 255 g_date_time_unref(dt); |
|
| 256 logs = logs->next; |
|
| 257 } |
|
| 258 } |
|
| 259 |
|
| 260 static FinchLogViewer * |
|
| 261 display_log_viewer(struct log_viewer_hash *ht, GList *logs, const char *title, |
|
| 262 int log_size) |
|
| 263 { |
|
| 264 FinchLogViewer *lv; |
|
| 265 char *text; |
|
| 266 GntWidget *vbox, *hbox; |
|
| 267 GntWidget *size_label; |
|
| 268 |
|
| 269 if (logs == NULL) |
|
| 270 { |
|
| 271 /* No logs were found. */ |
|
| 272 const char *log_preferences = NULL; |
|
| 273 |
|
| 274 if (ht == NULL) { |
|
| 275 if (!purple_prefs_get_bool("/purple/logging/log_system")) |
|
| 276 log_preferences = _("System events will only be logged if the \"Log all status changes to system log\" preference is enabled."); |
|
| 277 } else { |
|
| 278 if (ht->type == PURPLE_LOG_IM) { |
|
| 279 if (!purple_prefs_get_bool("/purple/logging/log_ims")) |
|
| 280 log_preferences = _("Instant messages will only be logged if the \"Log all instant messages\" preference is enabled."); |
|
| 281 } else if (ht->type == PURPLE_LOG_CHAT) { |
|
| 282 if (!purple_prefs_get_bool("/purple/logging/log_chats")) |
|
| 283 log_preferences = _("Chats will only be logged if the \"Log all chats\" preference is enabled."); |
|
| 284 } |
|
| 285 g_free(ht->username); |
|
| 286 g_free(ht); |
|
| 287 } |
|
| 288 |
|
| 289 purple_notify_info(NULL, title, _("No logs were found"), log_preferences, NULL); |
|
| 290 return NULL; |
|
| 291 } |
|
| 292 |
|
| 293 lv = g_new0(FinchLogViewer, 1); |
|
| 294 lv->logs = logs; |
|
| 295 |
|
| 296 if (ht != NULL) |
|
| 297 g_hash_table_insert(log_viewers, ht, lv); |
|
| 298 |
|
| 299 /* Window ***********/ |
|
| 300 lv->window = gnt_vwindow_new(FALSE); |
|
| 301 gnt_box_set_title(GNT_BOX(lv->window), title); |
|
| 302 gnt_box_set_toplevel(GNT_BOX(lv->window), TRUE); |
|
| 303 gnt_box_set_pad(GNT_BOX(lv->window), 0); |
|
| 304 g_signal_connect(G_OBJECT(lv->window), "destroy", G_CALLBACK(destroy_cb), ht); |
|
| 305 |
|
| 306 vbox = gnt_vbox_new(FALSE); |
|
| 307 gnt_box_add_widget(GNT_BOX(lv->window), vbox); |
|
| 308 |
|
| 309 /* Label ************/ |
|
| 310 text = g_strdup(title); |
|
| 311 lv->label = gnt_label_new_with_format(text, GNT_TEXT_FLAG_BOLD); |
|
| 312 g_free(text); |
|
| 313 gnt_box_add_widget(GNT_BOX(vbox), lv->label); |
|
| 314 |
|
| 315 hbox = gnt_hbox_new(FALSE); |
|
| 316 gnt_box_add_widget(GNT_BOX(vbox), hbox); |
|
| 317 /* List *************/ |
|
| 318 lv->tree = gnt_tree_new(); |
|
| 319 gnt_widget_set_size(lv->tree, 30, 0); |
|
| 320 populate_log_tree(lv); |
|
| 321 g_signal_connect (G_OBJECT(lv->tree), "selection-changed", |
|
| 322 G_CALLBACK (log_select_cb), |
|
| 323 lv); |
|
| 324 gnt_box_add_widget(GNT_BOX(hbox), lv->tree); |
|
| 325 |
|
| 326 /* Viewer ************/ |
|
| 327 lv->text = gnt_text_view_new(); |
|
| 328 gnt_box_add_widget(GNT_BOX(hbox), lv->text); |
|
| 329 gnt_text_view_set_flag(GNT_TEXT_VIEW(lv->text), GNT_TEXT_VIEW_TOP_ALIGN); |
|
| 330 |
|
| 331 hbox = gnt_hbox_new(FALSE); |
|
| 332 gnt_box_add_widget(GNT_BOX(vbox), hbox); |
|
| 333 /* Log size ************/ |
|
| 334 if (log_size) { |
|
| 335 char *sz_txt = g_format_size(log_size); |
|
| 336 text = g_strdup_printf("%s %s", _("Total log size:"), sz_txt); |
|
| 337 size_label = gnt_label_new(text); |
|
| 338 gnt_box_add_widget(GNT_BOX(hbox), size_label); |
|
| 339 g_free(sz_txt); |
|
| 340 g_free(text); |
|
| 341 } |
|
| 342 |
|
| 343 /* Search box **********/ |
|
| 344 gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Scroll/Search: "))); |
|
| 345 lv->entry = gnt_entry_new(""); |
|
| 346 gnt_box_add_widget(GNT_BOX(hbox), lv->entry); |
|
| 347 g_signal_connect(GNT_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv); |
|
| 348 |
|
| 349 gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(lv->text), lv->entry); |
|
| 350 gnt_text_view_attach_pager_widget(GNT_TEXT_VIEW(lv->text), lv->entry); |
|
| 351 |
|
| 352 gnt_widget_show(lv->window); |
|
| 353 |
|
| 354 return lv; |
|
| 355 } |
|
| 356 |
|
| 357 static void |
|
| 358 our_logging_blows(PurpleLogSet *set, PurpleLogSet *setagain, GList **list) |
|
| 359 { |
|
| 360 /* The iteration happens on the first list. So we use the shorter list in front */ |
|
| 361 if (set->type != PURPLE_LOG_IM) |
|
| 362 return; |
|
| 363 *list = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, set->name, set->account), *list); |
|
| 364 } |
|
| 365 |
|
| 366 void finch_log_show(PurpleLogType type, const char *username, PurpleAccount *account) |
|
| 367 { |
|
| 368 struct log_viewer_hash *ht; |
|
| 369 FinchLogViewer *lv = NULL; |
|
| 370 const char *name = username; |
|
| 371 char *title; |
|
| 372 GList *logs = NULL; |
|
| 373 int size = 0; |
|
| 374 |
|
| 375 if (type != PURPLE_LOG_IM) { |
|
| 376 g_return_if_fail(account != NULL); |
|
| 377 g_return_if_fail(username != NULL); |
|
| 378 } |
|
| 379 |
|
| 380 ht = g_new0(struct log_viewer_hash, 1); |
|
| 381 |
|
| 382 ht->type = type; |
|
| 383 ht->username = g_strdup(username); |
|
| 384 ht->account = account; |
|
| 385 |
|
| 386 if (log_viewers == NULL) { |
|
| 387 log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal); |
|
| 388 } else if ((lv = g_hash_table_lookup(log_viewers, ht))) { |
|
| 389 gnt_window_present(lv->window); |
|
| 390 g_free(ht->username); |
|
| 391 g_free(ht); |
|
| 392 return; |
|
| 393 } |
|
| 394 |
|
| 395 if (type == PURPLE_LOG_CHAT) { |
|
| 396 PurpleChat *chat; |
|
| 397 |
|
| 398 chat = purple_blist_find_chat(account, username); |
|
| 399 if (chat != NULL) |
|
| 400 name = purple_chat_get_name(chat); |
|
| 401 |
|
| 402 title = g_strdup_printf(_("Conversations in %s"), name); |
|
| 403 } else { |
|
| 404 PurpleBuddy *buddy; |
|
| 405 |
|
| 406 if (username) { |
|
| 407 buddy = purple_blist_find_buddy(account, username); |
|
| 408 if (buddy != NULL) |
|
| 409 name = purple_buddy_get_contact_alias(buddy); |
|
| 410 title = g_strdup_printf(_("Conversations with %s"), name); |
|
| 411 } else { |
|
| 412 title = g_strdup(_("All Conversations")); |
|
| 413 } |
|
| 414 } |
|
| 415 |
|
| 416 if (username) { |
|
| 417 logs = purple_log_get_logs(type, username, account); |
|
| 418 size = purple_log_get_total_size(type, username, account); |
|
| 419 } else { |
|
| 420 /* This will happen only for IMs */ |
|
| 421 GHashTable *table = purple_log_get_log_sets(); |
|
| 422 g_hash_table_foreach(table, (GHFunc)our_logging_blows, &logs); |
|
| 423 g_hash_table_destroy(table); |
|
| 424 logs = g_list_sort(logs, purple_log_compare); |
|
| 425 size = 0; |
|
| 426 } |
|
| 427 |
|
| 428 display_log_viewer(ht, logs, title, size); |
|
| 429 |
|
| 430 g_free(title); |
|
| 431 } |
|
| 432 |
|
| 433 void finch_log_show_contact(PurpleContact *contact) |
|
| 434 { |
|
| 435 struct log_viewer_hash *ht; |
|
| 436 PurpleBlistNode *child; |
|
| 437 FinchLogViewer *lv = NULL; |
|
| 438 GList *logs = NULL; |
|
| 439 const char *name = NULL; |
|
| 440 char *title; |
|
| 441 int total_log_size = 0; |
|
| 442 |
|
| 443 g_return_if_fail(contact != NULL); |
|
| 444 |
|
| 445 ht = g_new0(struct log_viewer_hash, 1); |
|
| 446 ht->type = PURPLE_LOG_IM; |
|
| 447 ht->contact = contact; |
|
| 448 |
|
| 449 if (log_viewers == NULL) { |
|
| 450 log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal); |
|
| 451 } else if ((lv = g_hash_table_lookup(log_viewers, ht))) { |
|
| 452 gnt_window_present(lv->window); |
|
| 453 g_free(ht); |
|
| 454 return; |
|
| 455 } |
|
| 456 |
|
| 457 for (child = purple_blist_node_get_first_child((PurpleBlistNode*)contact); child; |
|
| 458 child = purple_blist_node_get_sibling_next(child)) { |
|
| 459 const char *name; |
|
| 460 PurpleAccount *account; |
|
| 461 if (!PURPLE_IS_BUDDY(child)) |
|
| 462 continue; |
|
| 463 |
|
| 464 name = purple_buddy_get_name((PurpleBuddy *)child); |
|
| 465 account = purple_buddy_get_account((PurpleBuddy *)child); |
|
| 466 logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, name, |
|
| 467 account), logs); |
|
| 468 total_log_size += purple_log_get_total_size(PURPLE_LOG_IM, name, account); |
|
| 469 } |
|
| 470 logs = g_list_sort(logs, purple_log_compare); |
|
| 471 |
|
| 472 name = purple_contact_get_alias(contact); |
|
| 473 if (!name) |
|
| 474 name = purple_buddy_get_contact_alias(purple_contact_get_priority_buddy(contact)); |
|
| 475 |
|
| 476 /* This will happen if the contact doesn't have an alias, |
|
| 477 * and none of the contact's buddies are online. |
|
| 478 * There is probably a better way to deal with this. */ |
|
| 479 if (name == NULL) { |
|
| 480 child = purple_blist_node_get_first_child((PurpleBlistNode*)contact); |
|
| 481 if (PURPLE_IS_BUDDY(child)) { |
|
| 482 name = purple_buddy_get_contact_alias((PurpleBuddy *)child); |
|
| 483 } |
|
| 484 if (name == NULL) |
|
| 485 name = ""; |
|
| 486 } |
|
| 487 |
|
| 488 title = g_strdup_printf(_("Conversations with %s"), name); |
|
| 489 display_log_viewer(ht, logs, title, total_log_size); |
|
| 490 g_free(title); |
|
| 491 } |
|
| 492 |
|
| 493 void finch_syslog_show() |
|
| 494 { |
|
| 495 GList *accounts = NULL; |
|
| 496 GList *logs = NULL; |
|
| 497 |
|
| 498 if (syslog_viewer != NULL) { |
|
| 499 gnt_window_present(syslog_viewer->window); |
|
| 500 return; |
|
| 501 } |
|
| 502 |
|
| 503 for(accounts = purple_accounts_get_all(); accounts != NULL; accounts = accounts->next) { |
|
| 504 |
|
| 505 PurpleAccount *account = (PurpleAccount *)accounts->data; |
|
| 506 if(purple_account_get_protocol(account) == NULL) |
|
| 507 continue; |
|
| 508 |
|
| 509 logs = g_list_concat(purple_log_get_system_logs(account), logs); |
|
| 510 } |
|
| 511 logs = g_list_sort(logs, purple_log_compare); |
|
| 512 |
|
| 513 syslog_viewer = display_log_viewer(NULL, logs, _("System Log"), 0); |
|
| 514 } |
|
| 515 |
|
| 516 /**************************************************************************** |
|
| 517 * GNT LOG SUBSYSTEM ******************************************************* |
|
| 518 ****************************************************************************/ |
|
| 519 |
|
| 520 void * |
|
| 521 finch_log_get_handle(void) |
|
| 522 { |
|
| 523 static int handle; |
|
| 524 |
|
| 525 return &handle; |
|
| 526 } |
|
| 527 |
|
| 528 void finch_log_init(void) |
|
| 529 { |
|
| 530 void *handle = finch_log_get_handle(); |
|
| 531 |
|
| 532 purple_signal_register(handle, "log-displaying", |
|
| 533 purple_marshal_VOID__POINTER_POINTER, |
|
| 534 G_TYPE_NONE, 2, |
|
| 535 G_TYPE_POINTER, /* (FinchLogViewer *) */ |
|
| 536 PURPLE_TYPE_LOG); |
|
| 537 } |
|
| 538 |
|
| 539 void |
|
| 540 finch_log_uninit(void) |
|
| 541 { |
|
| 542 purple_signals_unregister_by_instance(finch_log_get_handle()); |
|
| 543 } |
|