Mercurial > pidgin
comparison src/pounce.c @ 5875:448f2f4ca3ec
[gaim-migrate @ 6307]
Rewrote the pounce framework.. yes, again. But now it saves! OOhh!! Neato.
Things are cleaner too. AND I CHANGED THE OK BUTTON TO SAVE!
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Sun, 15 Jun 2003 02:03:23 +0000 |
parents | 059d95c67cda |
children | 9e54bb2ee3b5 |
comparison
equal
deleted
inserted
replaced
5874:964e4f94fc56 | 5875:448f2f4ca3ec |
---|---|
28 #include "pounce.h" | 28 #include "pounce.h" |
29 #include "util.h" | 29 #include "util.h" |
30 | 30 |
31 typedef struct | 31 typedef struct |
32 { | 32 { |
33 GString *buffer; | |
34 | |
35 GaimPounce *pounce; | |
36 GaimPounceEvent events; | |
37 | |
38 char *ui_name; | |
39 char *pouncee; | |
40 char *protocol_id; | |
41 char *event_type; | |
42 char *action_name; | |
43 char *param_name; | |
44 char *account_name; | |
45 | |
46 } PounceParserData; | |
47 | |
48 typedef struct | |
49 { | |
33 char *name; | 50 char *name; |
34 | 51 |
35 gboolean enabled; | 52 gboolean enabled; |
36 | 53 |
37 GHashTable *atts; | 54 GHashTable *atts; |
38 | 55 |
39 } GaimPounceActionData; | 56 } GaimPounceActionData; |
40 | 57 |
41 | 58 typedef struct |
42 static GList *pounces = NULL; | 59 { |
43 static guint pounces_save_timer = 0; | 60 char *ui; |
44 static gboolean pounces_loaded = FALSE; | 61 GaimPounceCb cb; |
62 void (*new_pounce)(GaimPounce *); | |
63 void (*free_pounce)(GaimPounce *); | |
64 | |
65 } GaimPounceHandler; | |
66 | |
67 | |
68 static GHashTable *pounce_handlers = NULL; | |
69 static GList *pounces = NULL; | |
70 static guint pounces_save_timer = 0; | |
71 static gboolean pounces_loaded = FALSE; | |
72 | |
45 | 73 |
46 static GaimPounceActionData * | 74 static GaimPounceActionData * |
47 find_action_data(const GaimPounce *pounce, const char *name) | 75 find_action_data(const GaimPounce *pounce, const char *name) |
48 { | 76 { |
49 GaimPounceActionData *action; | 77 GaimPounceActionData *action; |
84 pounces_save_timer = g_timeout_add(5000, pounces_save_cb, NULL); | 112 pounces_save_timer = g_timeout_add(5000, pounces_save_cb, NULL); |
85 } | 113 } |
86 | 114 |
87 GaimPounce * | 115 GaimPounce * |
88 gaim_pounce_new(const char *ui_type, GaimAccount *pouncer, | 116 gaim_pounce_new(const char *ui_type, GaimAccount *pouncer, |
89 const char *pouncee, GaimPounceEvent event, | 117 const char *pouncee, GaimPounceEvent event) |
90 GaimPounceCb cb, void *data, void (*free)(void *)) | |
91 { | 118 { |
92 GaimPounce *pounce; | 119 GaimPounce *pounce; |
120 GaimPounceHandler *handler; | |
93 | 121 |
94 g_return_val_if_fail(ui_type != NULL, NULL); | 122 g_return_val_if_fail(ui_type != NULL, NULL); |
95 g_return_val_if_fail(pouncer != NULL, NULL); | 123 g_return_val_if_fail(pouncer != NULL, NULL); |
96 g_return_val_if_fail(pouncee != NULL, NULL); | 124 g_return_val_if_fail(pouncee != NULL, NULL); |
97 g_return_val_if_fail(event != 0, NULL); | 125 g_return_val_if_fail(event != 0, NULL); |
98 g_return_val_if_fail(cb != NULL, NULL); | |
99 | 126 |
100 pounce = g_new0(GaimPounce, 1); | 127 pounce = g_new0(GaimPounce, 1); |
101 | 128 |
102 pounce->ui_type = g_strdup(ui_type); | 129 pounce->ui_type = g_strdup(ui_type); |
103 pounce->pouncer = pouncer; | 130 pounce->pouncer = pouncer; |
104 pounce->pouncee = g_strdup(pouncee); | 131 pounce->pouncee = g_strdup(pouncee); |
105 pounce->events = event; | 132 pounce->events = event; |
106 pounce->callback = cb; | |
107 pounce->data = data; | |
108 pounce->free = free; | |
109 | 133 |
110 pounce->actions = g_hash_table_new_full(g_str_hash, g_str_equal, | 134 pounce->actions = g_hash_table_new_full(g_str_hash, g_str_equal, |
111 g_free, free_action_data); | 135 g_free, free_action_data); |
112 | 136 |
137 handler = g_hash_table_lookup(pounce_handlers, pounce->ui_type); | |
138 | |
139 if (handler != NULL && handler->new_pounce != NULL) | |
140 handler->new_pounce(pounce); | |
141 | |
113 pounces = g_list_append(pounces, pounce); | 142 pounces = g_list_append(pounces, pounce); |
114 | 143 |
115 return pounce; | 144 return pounce; |
116 } | 145 } |
117 | 146 |
118 void | 147 void |
119 gaim_pounce_destroy(GaimPounce *pounce) | 148 gaim_pounce_destroy(GaimPounce *pounce) |
120 { | 149 { |
150 GaimPounceHandler *handler; | |
151 | |
121 g_return_if_fail(pounce != NULL); | 152 g_return_if_fail(pounce != NULL); |
153 | |
154 handler = g_hash_table_lookup(pounce_handlers, pounce->ui_type); | |
122 | 155 |
123 pounces = g_list_remove(pounces, pounce); | 156 pounces = g_list_remove(pounces, pounce); |
124 | 157 |
125 if (pounce->ui_type != NULL) g_free(pounce->ui_type); | 158 if (pounce->ui_type != NULL) g_free(pounce->ui_type); |
126 if (pounce->pouncee != NULL) g_free(pounce->pouncee); | 159 if (pounce->pouncee != NULL) g_free(pounce->pouncee); |
127 | 160 |
128 g_hash_table_destroy(pounce->actions); | 161 g_hash_table_destroy(pounce->actions); |
129 | 162 |
130 if (pounce->free != NULL && pounce->data != NULL) | 163 if (handler != NULL && handler->free_pounce != NULL) |
131 pounce->free(pounce->data); | 164 handler->free_pounce(pounce); |
132 | 165 |
133 g_free(pounce); | 166 g_free(pounce); |
134 | 167 |
135 schedule_pounces_save(); | 168 schedule_pounces_save(); |
136 } | 169 } |
325 void | 358 void |
326 gaim_pounce_execute(const GaimAccount *pouncer, const char *pouncee, | 359 gaim_pounce_execute(const GaimAccount *pouncer, const char *pouncee, |
327 GaimPounceEvent events) | 360 GaimPounceEvent events) |
328 { | 361 { |
329 GaimPounce *pounce; | 362 GaimPounce *pounce; |
363 GaimPounceHandler *handler; | |
330 GList *l, *l_next; | 364 GList *l, *l_next; |
331 | 365 |
332 g_return_if_fail(pouncer != NULL); | 366 g_return_if_fail(pouncer != NULL); |
333 g_return_if_fail(pouncee != NULL); | 367 g_return_if_fail(pouncee != NULL); |
334 g_return_if_fail(events != GAIM_POUNCE_NONE); | 368 g_return_if_fail(events != GAIM_POUNCE_NONE); |
339 | 373 |
340 if ((gaim_pounce_get_events(pounce) & events) && | 374 if ((gaim_pounce_get_events(pounce) & events) && |
341 (gaim_pounce_get_pouncer(pounce) == pouncer) && | 375 (gaim_pounce_get_pouncer(pounce) == pouncer) && |
342 !strcmp(gaim_pounce_get_pouncee(pounce), pouncee)) { | 376 !strcmp(gaim_pounce_get_pouncee(pounce), pouncee)) { |
343 | 377 |
344 if (pounce->callback != NULL) { | 378 handler = g_hash_table_lookup(pounce_handlers, pounce->ui_type); |
345 pounce->callback(pounce, events, gaim_pounce_get_data(pounce)); | 379 |
380 if (handler != NULL && handler->cb != NULL) { | |
381 handler->cb(pounce, events, gaim_pounce_get_data(pounce)); | |
346 | 382 |
347 if (!gaim_pounce_get_save(pounce)) | 383 if (!gaim_pounce_get_save(pounce)) |
348 gaim_pounce_destroy(pounce); | 384 gaim_pounce_destroy(pounce); |
349 } | 385 } |
350 } | 386 } |
374 } | 410 } |
375 | 411 |
376 return NULL; | 412 return NULL; |
377 } | 413 } |
378 | 414 |
415 /* XML Stuff */ | |
416 static void | |
417 free_parser_data(gpointer user_data) | |
418 { | |
419 PounceParserData *data = user_data; | |
420 | |
421 if (data->buffer != NULL) | |
422 g_string_free(data->buffer, TRUE); | |
423 | |
424 if (data->ui_name != NULL) g_free(data->ui_name); | |
425 if (data->pouncee != NULL) g_free(data->pouncee); | |
426 if (data->protocol_id != NULL) g_free(data->protocol_id); | |
427 if (data->event_type != NULL) g_free(data->event_type); | |
428 if (data->action_name != NULL) g_free(data->action_name); | |
429 if (data->param_name != NULL) g_free(data->param_name); | |
430 if (data->account_name != NULL) g_free(data->account_name); | |
431 | |
432 g_free(data); | |
433 } | |
434 | |
435 static void | |
436 start_element_handler(GMarkupParseContext *context, | |
437 const gchar *element_name, | |
438 const gchar **attribute_names, | |
439 const gchar **attribute_values, | |
440 gpointer user_data, GError **error) | |
441 { | |
442 PounceParserData *data = user_data; | |
443 GHashTable *atts; | |
444 int i; | |
445 | |
446 atts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
447 | |
448 for (i = 0; attribute_names[i] != NULL; i++) { | |
449 g_hash_table_insert(atts, g_strdup(attribute_names[i]), | |
450 g_strdup(attribute_values[i])); | |
451 } | |
452 | |
453 if (data->buffer != NULL) { | |
454 g_string_free(data->buffer, TRUE); | |
455 data->buffer = NULL; | |
456 } | |
457 | |
458 if (!strcmp(element_name, "pounce")) { | |
459 const char *ui = g_hash_table_lookup(atts, "ui"); | |
460 | |
461 if (ui == NULL) { | |
462 gaim_debug(GAIM_DEBUG_ERROR, "pounce", | |
463 "Unset 'ui' parameter for pounce!\n"); | |
464 } | |
465 else | |
466 data->ui_name = g_strdup(ui); | |
467 | |
468 data->events = 0; | |
469 } | |
470 else if (!strcmp(element_name, "account")) { | |
471 const char *protocol_id = g_hash_table_lookup(atts, "protocol"); | |
472 | |
473 if (protocol_id == NULL) { | |
474 gaim_debug(GAIM_DEBUG_ERROR, "pounce", | |
475 "Unset 'protocol' parameter for account!\n"); | |
476 } | |
477 else | |
478 data->protocol_id = g_strdup(protocol_id); | |
479 } | |
480 else if (!strcmp(element_name, "event")) { | |
481 const char *type = g_hash_table_lookup(atts, "type"); | |
482 | |
483 if (type == NULL) { | |
484 gaim_debug(GAIM_DEBUG_ERROR, "pounce", | |
485 "Unset 'type' parameter for event!\n"); | |
486 } | |
487 else | |
488 data->event_type = g_strdup(type); | |
489 } | |
490 else if (!strcmp(element_name, "action")) { | |
491 const char *type = g_hash_table_lookup(atts, "type"); | |
492 | |
493 if (type == NULL) { | |
494 gaim_debug(GAIM_DEBUG_ERROR, "pounce", | |
495 "Unset 'type' parameter for action!\n"); | |
496 } | |
497 else | |
498 data->action_name = g_strdup(type); | |
499 } | |
500 else if (!strcmp(element_name, "param")) { | |
501 const char *param_name = g_hash_table_lookup(atts, "name"); | |
502 | |
503 if (param_name == NULL) { | |
504 gaim_debug(GAIM_DEBUG_ERROR, "pounce", | |
505 "Unset 'name' parameter for param!\n"); | |
506 } | |
507 else | |
508 data->param_name = g_strdup(param_name); | |
509 } | |
510 | |
511 g_hash_table_destroy(atts); | |
512 } | |
513 | |
514 static void | |
515 end_element_handler(GMarkupParseContext *context, const gchar *element_name, | |
516 gpointer user_data, GError **error) | |
517 { | |
518 PounceParserData *data = user_data; | |
519 gchar *buffer = NULL; | |
520 | |
521 if (data->buffer != NULL) { | |
522 buffer = g_string_free(data->buffer, FALSE); | |
523 data->buffer = NULL; | |
524 } | |
525 | |
526 if (!strcmp(element_name, "account")) { | |
527 data->account_name = g_strdup(buffer); | |
528 } | |
529 else if (!strcmp(element_name, "pouncee")) { | |
530 data->pouncee = g_strdup(buffer); | |
531 } | |
532 else if (!strcmp(element_name, "event")) { | |
533 if (!strcmp(data->event_type, "sign-on")) | |
534 data->events |= GAIM_POUNCE_SIGNON; | |
535 else if (!strcmp(data->event_type, "sign-off")) | |
536 data->events |= GAIM_POUNCE_SIGNOFF; | |
537 else if (!strcmp(data->event_type, "away")) | |
538 data->events |= GAIM_POUNCE_AWAY; | |
539 else if (!strcmp(data->event_type, "return-from-away")) | |
540 data->events |= GAIM_POUNCE_AWAY_RETURN; | |
541 else if (!strcmp(data->event_type, "idle")) | |
542 data->events |= GAIM_POUNCE_IDLE; | |
543 else if (!strcmp(data->event_type, "return-from-idle")) | |
544 data->events |= GAIM_POUNCE_IDLE_RETURN; | |
545 else if (!strcmp(data->event_type, "typing")) | |
546 data->events |= GAIM_POUNCE_TYPING; | |
547 else if (!strcmp(data->event_type, "stop-typing")) | |
548 data->events |= GAIM_POUNCE_TYPING_STOPPED; | |
549 | |
550 g_free(data->event_type); | |
551 data->event_type = NULL; | |
552 } | |
553 else if (!strcmp(element_name, "action")) { | |
554 gaim_pounce_action_set_enabled(data->pounce, data->action_name, TRUE); | |
555 | |
556 g_free(data->action_name); | |
557 data->action_name = NULL; | |
558 } | |
559 else if (!strcmp(element_name, "param")) { | |
560 gaim_pounce_action_set_attribute(data->pounce, data->action_name, | |
561 data->param_name, buffer); | |
562 | |
563 g_free(data->param_name); | |
564 data->param_name = NULL; | |
565 } | |
566 else if (!strcmp(element_name, "events")) { | |
567 GList *l; | |
568 GaimAccount *account; | |
569 GaimProtocol protocol = -1; | |
570 | |
571 for (l = gaim_plugins_get_protocols(); l != NULL; l = l->next) { | |
572 GaimPlugin *plugin = (GaimPlugin *)l->data; | |
573 | |
574 if (GAIM_IS_PROTOCOL_PLUGIN(plugin)) { | |
575 if (!strcmp(plugin->info->id, data->protocol_id)) { | |
576 protocol = GAIM_PLUGIN_PROTOCOL_INFO(plugin)->protocol; | |
577 | |
578 break; | |
579 } | |
580 } | |
581 } | |
582 | |
583 account = gaim_accounts_find(data->account_name, protocol); | |
584 | |
585 g_free(data->account_name); | |
586 g_free(data->protocol_id); | |
587 | |
588 data->account_name = NULL; | |
589 data->protocol_id = NULL; | |
590 | |
591 if (account == NULL) { | |
592 gaim_debug(GAIM_DEBUG_ERROR, "pounce", | |
593 "Account for pounce not found!\n"); | |
594 } | |
595 else { | |
596 gaim_debug(GAIM_DEBUG_INFO, "pounce", | |
597 "Creating pounce: %s, %s\n", data->ui_name, | |
598 data->pouncee); | |
599 | |
600 data->pounce = gaim_pounce_new(data->ui_name, account, | |
601 data->pouncee, data->events); | |
602 } | |
603 | |
604 g_free(data->pouncee); | |
605 data->pouncee = NULL; | |
606 } | |
607 else if (!strcmp(element_name, "pounce")) { | |
608 data->pounce = NULL; | |
609 data->events = 0; | |
610 | |
611 if (data->ui_name != NULL) g_free(data->ui_name); | |
612 if (data->pouncee != NULL) g_free(data->pouncee); | |
613 if (data->protocol_id != NULL) g_free(data->protocol_id); | |
614 if (data->event_type != NULL) g_free(data->event_type); | |
615 if (data->action_name != NULL) g_free(data->action_name); | |
616 if (data->param_name != NULL) g_free(data->param_name); | |
617 if (data->account_name != NULL) g_free(data->account_name); | |
618 | |
619 data->ui_name = NULL; | |
620 data->pounce = NULL; | |
621 data->protocol_id = NULL; | |
622 data->event_type = NULL; | |
623 data->action_name = NULL; | |
624 data->param_name = NULL; | |
625 data->account_name = NULL; | |
626 } | |
627 | |
628 if (buffer != NULL) | |
629 g_free(buffer); | |
630 } | |
631 | |
632 static void | |
633 text_handler(GMarkupParseContext *context, const gchar *text, | |
634 gsize text_len, gpointer user_data, GError **error) | |
635 { | |
636 PounceParserData *data = user_data; | |
637 | |
638 if (data->buffer == NULL) | |
639 data->buffer = g_string_new_len(text, text_len); | |
640 else | |
641 g_string_append_len(data->buffer, text, text_len); | |
642 } | |
643 | |
644 static GMarkupParser pounces_parser = | |
645 { | |
646 start_element_handler, | |
647 end_element_handler, | |
648 text_handler, | |
649 NULL, | |
650 NULL | |
651 }; | |
652 | |
379 gboolean | 653 gboolean |
380 gaim_pounces_load(void) | 654 gaim_pounces_load(void) |
381 { | 655 { |
656 gchar *filename = g_build_filename(gaim_user_dir(), "pounces.xml", NULL); | |
657 gchar *contents = NULL; | |
658 gsize length; | |
659 GMarkupParseContext *context; | |
660 GError *error = NULL; | |
661 PounceParserData *parser_data; | |
662 | |
663 if (filename == NULL) { | |
664 pounces_loaded = TRUE; | |
665 return FALSE; | |
666 } | |
667 | |
668 if (!g_file_get_contents(filename, &contents, &length, &error)) { | |
669 gaim_debug(GAIM_DEBUG_ERROR, "pounces", | |
670 "Error reading pounces: %s\n", error->message); | |
671 | |
672 g_error_free(error); | |
673 | |
674 pounces_loaded = TRUE; | |
675 return FALSE; | |
676 } | |
677 | |
678 parser_data = g_new0(PounceParserData, 1); | |
679 | |
680 context = g_markup_parse_context_new(&pounces_parser, 0, | |
681 parser_data, free_parser_data); | |
682 | |
683 if (!g_markup_parse_context_parse(context, contents, length, NULL)) { | |
684 g_markup_parse_context_free(context); | |
685 g_free(contents); | |
686 | |
687 pounces_loaded = TRUE; | |
688 | |
689 return FALSE; | |
690 } | |
691 | |
692 if (!g_markup_parse_context_end_parse(context, NULL)) { | |
693 gaim_debug(GAIM_DEBUG_ERROR, "pounces", "Error parsing %s\n", | |
694 filename); | |
695 | |
696 g_markup_parse_context_free(context); | |
697 g_free(contents); | |
698 pounces_loaded = TRUE; | |
699 | |
700 return FALSE; | |
701 } | |
702 | |
703 g_markup_parse_context_free(context); | |
704 g_free(contents); | |
705 | |
706 g_free(filename); | |
707 | |
382 pounces_loaded = TRUE; | 708 pounces_loaded = TRUE; |
383 | 709 |
384 return TRUE; | 710 return TRUE; |
385 } | 711 } |
386 | 712 |
442 pouncer->protocol_id, pouncer_name); | 768 pouncer->protocol_id, pouncer_name); |
443 fprintf(fp, " <pouncee>%s</pouncee>\n", gaim_pounce_get_pouncee(pounce)); | 769 fprintf(fp, " <pouncee>%s</pouncee>\n", gaim_pounce_get_pouncee(pounce)); |
444 fprintf(fp, " <events>\n"); | 770 fprintf(fp, " <events>\n"); |
445 | 771 |
446 if (events & GAIM_POUNCE_SIGNON) | 772 if (events & GAIM_POUNCE_SIGNON) |
447 fprintf(fp, " <event type='sign-on'>\n"); | 773 fprintf(fp, " <event type='sign-on'/>\n"); |
448 if (events & GAIM_POUNCE_SIGNOFF) | 774 if (events & GAIM_POUNCE_SIGNOFF) |
449 fprintf(fp, " <event type='sign-off'>\n"); | 775 fprintf(fp, " <event type='sign-off'/>\n"); |
450 if (events & GAIM_POUNCE_AWAY) | 776 if (events & GAIM_POUNCE_AWAY) |
451 fprintf(fp, " <event type='away'>\n"); | 777 fprintf(fp, " <event type='away'/>\n"); |
452 if (events & GAIM_POUNCE_AWAY_RETURN) | 778 if (events & GAIM_POUNCE_AWAY_RETURN) |
453 fprintf(fp, " <event type='return-from-away'>\n"); | 779 fprintf(fp, " <event type='return-from-away'/>\n"); |
454 if (events & GAIM_POUNCE_IDLE) | 780 if (events & GAIM_POUNCE_IDLE) |
455 fprintf(fp, " <event type='idle'>\n"); | 781 fprintf(fp, " <event type='idle'/>\n"); |
456 if (events & GAIM_POUNCE_IDLE_RETURN) | 782 if (events & GAIM_POUNCE_IDLE_RETURN) |
457 fprintf(fp, " <event type='return-from-idle'>\n"); | 783 fprintf(fp, " <event type='return-from-idle'/>\n"); |
458 if (events & GAIM_POUNCE_TYPING) | 784 if (events & GAIM_POUNCE_TYPING) |
459 fprintf(fp, " <event type='start-typing'>\n"); | 785 fprintf(fp, " <event type='start-typing'/>\n"); |
460 if (events & GAIM_POUNCE_TYPING_STOPPED) | 786 if (events & GAIM_POUNCE_TYPING_STOPPED) |
461 fprintf(fp, " <event type='stop-typing'>\n"); | 787 fprintf(fp, " <event type='stop-typing'/>\n"); |
462 | 788 |
463 fprintf(fp, " </events>\n"); | 789 fprintf(fp, " </events>\n"); |
464 fprintf(fp, " <actions>\n"); | 790 fprintf(fp, " <actions>\n"); |
465 | 791 |
466 g_hash_table_foreach(pounce->actions, write_action_parameter_list, fp); | 792 g_hash_table_foreach(pounce->actions, write_action_parameter_list, fp); |
528 | 854 |
529 g_free(filename); | 855 g_free(filename); |
530 g_free(filename_real); | 856 g_free(filename_real); |
531 } | 857 } |
532 | 858 |
859 void | |
860 gaim_pounces_register_handler(const char *ui, GaimPounceCb cb, | |
861 void (*new_pounce)(GaimPounce *pounce), | |
862 void (*free_pounce)(GaimPounce *pounce)) | |
863 { | |
864 GaimPounceHandler *handler; | |
865 | |
866 g_return_if_fail(ui != NULL); | |
867 g_return_if_fail(cb != NULL); | |
868 | |
869 handler = g_new0(GaimPounceHandler, 1); | |
870 | |
871 handler->ui = g_strdup(ui); | |
872 handler->cb = cb; | |
873 handler->new_pounce = new_pounce; | |
874 handler->free_pounce = free_pounce; | |
875 | |
876 g_hash_table_insert(pounce_handlers, g_strdup(ui), handler); | |
877 } | |
878 | |
879 void | |
880 gaim_pounces_unregister_handler(const char *ui) | |
881 { | |
882 g_return_if_fail(ui != NULL); | |
883 | |
884 g_hash_table_remove(pounce_handlers, ui); | |
885 } | |
886 | |
533 GList * | 887 GList * |
534 gaim_pounces_get_all(void) | 888 gaim_pounces_get_all(void) |
535 { | 889 { |
536 return pounces; | 890 return pounces; |
537 } | 891 } |
892 | |
893 static void | |
894 free_pounce_handler(gpointer user_data) | |
895 { | |
896 GaimPounceHandler *handler = (GaimPounceHandler *)user_data; | |
897 | |
898 g_free(handler->ui); | |
899 g_free(handler); | |
900 } | |
901 | |
902 void | |
903 gaim_pounces_init(void) | |
904 { | |
905 pounce_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, | |
906 g_free, free_pounce_handler); | |
907 } |