Coverage Report

Created: 2026-05-23 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pidgin/libpurple/notify.c
Line
Count
Source
1
/**
2
 * @file notify.c Notification API
3
 * @ingroup core
4
 */
5
6
/* purple
7
 *
8
 * Purple is the legal property of its developers, whose names are too numerous
9
 * to list here.  Please refer to the COPYRIGHT file distributed with this
10
 * source distribution.
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
25
 */
26
#define _PURPLE_NOTIFY_C_
27
28
#include "internal.h"
29
#include "dbus-maybe.h"
30
#include "glibcompat.h"
31
#include "notify.h"
32
33
static PurpleNotifyUiOps *notify_ui_ops = NULL;
34
static GList *handles = NULL;
35
36
typedef struct
37
{
38
  PurpleNotifyType type;
39
  void *handle;
40
  void *ui_handle;
41
  PurpleNotifyCloseCallback cb;
42
  gpointer cb_user_data;
43
} PurpleNotifyInfo;
44
45
/**
46
 * Definition of a user info entry
47
 */
48
struct _PurpleNotifyUserInfoEntry
49
{
50
  char *label;
51
  char *value;
52
  PurpleNotifyUserInfoEntryType type;
53
};
54
55
struct _PurpleNotifyUserInfo
56
{
57
  GList *user_info_entries;
58
};
59
60
void *
61
purple_notify_message(void *handle, PurpleNotifyMsgType type,
62
          const char *title, const char *primary,
63
          const char *secondary, PurpleNotifyCloseCallback cb, gpointer user_data)
64
0
{
65
0
  PurpleNotifyUiOps *ops;
66
67
0
  g_return_val_if_fail(primary != NULL, NULL);
68
69
0
  ops = purple_notify_get_ui_ops();
70
71
0
  if (ops != NULL && ops->notify_message != NULL) {
72
0
    void *ui_handle = ops->notify_message(type, title, primary,
73
0
                        secondary);
74
0
    if (ui_handle != NULL) {
75
76
0
      PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
77
0
      info->type = PURPLE_NOTIFY_MESSAGE;
78
0
      info->handle = handle;
79
0
      info->ui_handle = ui_handle;
80
0
      info->cb = cb;
81
0
      info->cb_user_data = user_data;
82
83
0
      handles = g_list_append(handles, info);
84
85
0
      return info->ui_handle;
86
0
    }
87
88
0
  }
89
90
0
  if (cb != NULL)
91
0
    cb(user_data);
92
93
0
  return NULL;
94
0
}
95
96
void *
97
purple_notify_email(void *handle, const char *subject, const char *from,
98
          const char *to, const char *url, PurpleNotifyCloseCallback cb,
99
          gpointer user_data)
100
0
{
101
0
  PurpleNotifyUiOps *ops;
102
103
0
  ops = purple_notify_get_ui_ops();
104
105
0
  if (ops != NULL && ops->notify_email != NULL) {
106
0
    void *ui_handle;
107
108
0
    purple_signal_emit(purple_notify_get_handle(), "displaying-email-notification",
109
0
               subject, from, to, url);
110
111
0
    ui_handle = ops->notify_email(handle, subject, from, to, url);
112
113
0
    if (ui_handle != NULL) {
114
115
0
      PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
116
0
      info->type = PURPLE_NOTIFY_EMAIL;
117
0
      info->handle = handle;
118
0
      info->ui_handle = ui_handle;
119
0
      info->cb = cb;
120
0
      info->cb_user_data = user_data;
121
122
0
      handles = g_list_append(handles, info);
123
124
0
      return info->ui_handle;
125
0
    }
126
0
  }
127
128
0
  if (cb != NULL)
129
0
    cb(user_data);
130
131
0
  return NULL;
132
0
}
133
134
void *
135
purple_notify_emails(void *handle, size_t count, gboolean detailed,
136
           const char **subjects, const char **froms,
137
           const char **tos, const char **urls,
138
           PurpleNotifyCloseCallback cb, gpointer user_data)
139
0
{
140
0
  PurpleNotifyUiOps *ops;
141
142
0
  if (count == 1) {
143
0
    return purple_notify_email(handle,
144
0
                 (subjects == NULL ? NULL : *subjects),
145
0
                 (froms    == NULL ? NULL : *froms),
146
0
                 (tos      == NULL ? NULL : *tos),
147
0
                 (urls     == NULL ? NULL : *urls),
148
0
                 cb, user_data);
149
0
  }
150
151
0
  ops = purple_notify_get_ui_ops();
152
153
0
  if (ops != NULL && ops->notify_emails != NULL) {
154
0
    void *ui_handle;
155
156
0
    purple_signal_emit(purple_notify_get_handle(), "displaying-emails-notification",
157
0
              subjects, froms, tos, urls, count);
158
159
0
    ui_handle = ops->notify_emails(handle, count, detailed, subjects,
160
0
                       froms, tos, urls);
161
162
0
    if (ui_handle != NULL) {
163
0
      PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
164
0
      info->type = PURPLE_NOTIFY_EMAILS;
165
0
      info->handle = handle;
166
0
      info->ui_handle = ui_handle;
167
0
      info->cb = cb;
168
0
      info->cb_user_data = user_data;
169
170
0
      handles = g_list_append(handles, info);
171
172
0
      return info->ui_handle;
173
0
    }
174
175
0
  }
176
177
0
  if (cb != NULL)
178
0
    cb(user_data);
179
180
0
  return NULL;
181
0
}
182
183
void *
184
purple_notify_formatted(void *handle, const char *title, const char *primary,
185
            const char *secondary, const char *text,
186
            PurpleNotifyCloseCallback cb, gpointer user_data)
187
0
{
188
0
  PurpleNotifyUiOps *ops;
189
190
0
  g_return_val_if_fail(primary != NULL, NULL);
191
192
0
  ops = purple_notify_get_ui_ops();
193
194
0
  if (ops != NULL && ops->notify_formatted != NULL) {
195
0
    void *ui_handle = ops->notify_formatted(title, primary, secondary, text);
196
197
0
    if (ui_handle != NULL) {
198
199
0
      PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
200
0
      info->type = PURPLE_NOTIFY_FORMATTED;
201
0
      info->handle = handle;
202
0
      info->ui_handle = ui_handle;
203
0
      info->cb = cb;
204
0
      info->cb_user_data = user_data;
205
206
0
      handles = g_list_append(handles, info);
207
208
0
      return info->ui_handle;
209
0
    }
210
0
  }
211
212
0
  if (cb != NULL)
213
0
    cb(user_data);
214
0
  return NULL;
215
0
}
216
217
void *
218
purple_notify_searchresults(PurpleConnection *gc, const char *title,
219
              const char *primary, const char *secondary,
220
              PurpleNotifySearchResults *results, PurpleNotifyCloseCallback cb,
221
              gpointer user_data)
222
0
{
223
0
  PurpleNotifyUiOps *ops;
224
225
0
  ops = purple_notify_get_ui_ops();
226
227
0
  if (ops != NULL && ops->notify_searchresults != NULL) {
228
0
    void *ui_handle = ops->notify_searchresults(gc, title, primary,
229
0
                          secondary, results, user_data);
230
0
    if (ui_handle != NULL) {
231
232
0
      PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
233
0
      info->type      = PURPLE_NOTIFY_SEARCHRESULTS;
234
0
      info->handle    = gc;
235
0
      info->ui_handle = ui_handle;
236
0
      info->cb = cb;
237
0
      info->cb_user_data = user_data;
238
239
0
      handles = g_list_append(handles, info);
240
241
0
      return info->ui_handle;
242
0
    }
243
0
  }
244
245
0
  if (cb != NULL)
246
0
    cb(user_data);
247
248
0
  return NULL;
249
0
}
250
251
void
252
purple_notify_searchresults_free(PurpleNotifySearchResults *results)
253
0
{
254
0
  GList *l;
255
256
0
  g_return_if_fail(results != NULL);
257
258
0
  for (l = results->buttons; l; l = g_list_delete_link(l, l)) {
259
0
    PurpleNotifySearchButton *button = l->data;
260
0
    g_free(button->label);
261
0
    g_free(button);
262
0
  }
263
264
0
  for (l = results->rows; l; l = g_list_delete_link(l, l)) {
265
0
    GList *row = l->data;
266
0
    g_list_free_full(row, (GDestroyNotify)g_free);
267
0
  }
268
269
0
  for (l = results->columns; l; l = g_list_delete_link(l, l)) {
270
0
    PurpleNotifySearchColumn *column = l->data;
271
0
    g_free(column->title);
272
0
    g_free(column);
273
0
  }
274
275
0
  g_free(results);
276
0
}
277
278
void
279
purple_notify_searchresults_new_rows(PurpleConnection *gc,
280
    PurpleNotifySearchResults *results,
281
    void *data)
282
0
{
283
0
  PurpleNotifyUiOps *ops;
284
285
0
  ops = purple_notify_get_ui_ops();
286
287
0
  if (ops != NULL && ops->notify_searchresults != NULL) {
288
0
    ops->notify_searchresults_new_rows(gc, results, data);
289
0
  }
290
0
}
291
292
void
293
purple_notify_searchresults_button_add(PurpleNotifySearchResults *results,
294
                   PurpleNotifySearchButtonType type,
295
                   PurpleNotifySearchResultsCallback cb)
296
0
{
297
0
  PurpleNotifySearchButton *button;
298
299
0
  g_return_if_fail(results != NULL);
300
0
  g_return_if_fail(cb != NULL);
301
302
0
  button = g_new0(PurpleNotifySearchButton, 1);
303
0
  button->callback = cb;
304
0
  button->type = type;
305
306
0
  results->buttons = g_list_append(results->buttons, button);
307
0
}
308
309
310
void
311
purple_notify_searchresults_button_add_labeled(PurpleNotifySearchResults *results,
312
                                             const char *label,
313
0
                                             PurpleNotifySearchResultsCallback cb) {
314
0
  PurpleNotifySearchButton *button;
315
316
0
  g_return_if_fail(results != NULL);
317
0
  g_return_if_fail(cb != NULL);
318
0
  g_return_if_fail(label != NULL);
319
0
  g_return_if_fail(*label != '\0');
320
321
0
  button = g_new0(PurpleNotifySearchButton, 1);
322
0
  button->callback = cb;
323
0
  button->type = PURPLE_NOTIFY_BUTTON_LABELED;
324
0
  button->label = g_strdup(label);
325
326
0
  results->buttons = g_list_append(results->buttons, button);
327
0
}
328
329
330
PurpleNotifySearchResults *
331
purple_notify_searchresults_new()
332
0
{
333
0
  PurpleNotifySearchResults *rs = g_new0(PurpleNotifySearchResults, 1);
334
335
0
  return rs;
336
0
}
337
338
void
339
purple_notify_searchresults_column_add(PurpleNotifySearchResults *results,
340
                   PurpleNotifySearchColumn *column)
341
0
{
342
0
  g_return_if_fail(results != NULL);
343
0
  g_return_if_fail(column  != NULL);
344
345
0
  results->columns = g_list_append(results->columns, column);
346
0
}
347
348
void purple_notify_searchresults_row_add(PurpleNotifySearchResults *results,
349
                     GList *row)
350
0
{
351
0
  g_return_if_fail(results != NULL);
352
0
  g_return_if_fail(row     != NULL);
353
354
0
  results->rows = g_list_append(results->rows, row);
355
0
}
356
357
PurpleNotifySearchColumn *
358
purple_notify_searchresults_column_new(const char *title)
359
0
{
360
0
  PurpleNotifySearchColumn *sc;
361
362
0
  g_return_val_if_fail(title != NULL, NULL);
363
364
0
  sc = g_new0(PurpleNotifySearchColumn, 1);
365
0
  sc->title = g_strdup(title);
366
367
0
  return sc;
368
0
}
369
370
guint
371
purple_notify_searchresults_get_columns_count(PurpleNotifySearchResults *results)
372
0
{
373
0
  g_return_val_if_fail(results != NULL, 0);
374
375
0
  return g_list_length(results->columns);
376
0
}
377
378
guint
379
purple_notify_searchresults_get_rows_count(PurpleNotifySearchResults *results)
380
0
{
381
0
  g_return_val_if_fail(results != NULL, 0);
382
383
0
  return g_list_length(results->rows);
384
0
}
385
386
char *
387
purple_notify_searchresults_column_get_title(PurpleNotifySearchResults *results,
388
                       unsigned int column_id)
389
0
{
390
0
  g_return_val_if_fail(results != NULL, NULL);
391
392
0
  return ((PurpleNotifySearchColumn *)g_list_nth_data(results->columns, column_id))->title;
393
0
}
394
395
GList *
396
purple_notify_searchresults_row_get(PurpleNotifySearchResults *results,
397
                  unsigned int row_id)
398
0
{
399
0
  g_return_val_if_fail(results != NULL, NULL);
400
401
0
  return g_list_nth_data(results->rows, row_id);
402
0
}
403
404
void *
405
purple_notify_userinfo(PurpleConnection *gc, const char *who,
406
               PurpleNotifyUserInfo *user_info, PurpleNotifyCloseCallback cb, gpointer user_data)
407
0
{
408
0
  PurpleNotifyUiOps *ops;
409
410
0
  g_return_val_if_fail(who != NULL, NULL);
411
412
0
  ops = purple_notify_get_ui_ops();
413
414
0
  if (ops != NULL && ops->notify_userinfo != NULL) {
415
0
    void *ui_handle;
416
417
0
    purple_signal_emit(purple_notify_get_handle(), "displaying-userinfo",
418
0
             purple_connection_get_account(gc), who, user_info);
419
420
0
    ui_handle = ops->notify_userinfo(gc, who, user_info);
421
422
0
    if (ui_handle != NULL) {
423
424
0
      PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
425
0
      info->type = PURPLE_NOTIFY_USERINFO;
426
0
      info->handle = gc;
427
0
      info->ui_handle = ui_handle;
428
0
      info->cb = cb;
429
0
      info->cb_user_data = user_data;
430
431
0
      handles = g_list_append(handles, info);
432
433
0
      return info->ui_handle;
434
0
    }
435
0
  }
436
437
0
  if (cb != NULL)
438
0
    cb(user_data);
439
440
0
  return NULL;
441
0
}
442
443
PurpleNotifyUserInfoEntry *
444
purple_notify_user_info_entry_new(const char *label, const char *value)
445
0
{
446
0
  PurpleNotifyUserInfoEntry *user_info_entry;
447
448
0
  user_info_entry = g_new0(PurpleNotifyUserInfoEntry, 1);
449
0
  PURPLE_DBUS_REGISTER_POINTER(user_info_entry, PurpleNotifyUserInfoEntry);
450
0
  user_info_entry->label = g_strdup(label);
451
0
  user_info_entry->value = g_strdup(value);
452
0
  user_info_entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR;
453
454
0
  return user_info_entry;
455
0
}
456
457
static void
458
purple_notify_user_info_entry_destroy(PurpleNotifyUserInfoEntry *user_info_entry)
459
0
{
460
0
  g_return_if_fail(user_info_entry != NULL);
461
462
0
  g_free(user_info_entry->label);
463
0
  g_free(user_info_entry->value);
464
0
  PURPLE_DBUS_UNREGISTER_POINTER(user_info_entry);
465
0
  g_free(user_info_entry);
466
0
}
467
468
PurpleNotifyUserInfo *
469
purple_notify_user_info_new()
470
0
{
471
0
  PurpleNotifyUserInfo *user_info;
472
473
0
  user_info = g_new0(PurpleNotifyUserInfo, 1);
474
0
  PURPLE_DBUS_REGISTER_POINTER(user_info, PurpleNotifyUserInfo);
475
0
  user_info->user_info_entries = NULL;
476
477
0
  return user_info;
478
0
}
479
480
void
481
purple_notify_user_info_destroy(PurpleNotifyUserInfo *user_info)
482
0
{
483
0
  GList *l;
484
485
0
  for (l = user_info->user_info_entries; l != NULL; l = l->next) {
486
0
    PurpleNotifyUserInfoEntry *user_info_entry = l->data;
487
488
0
    purple_notify_user_info_entry_destroy(user_info_entry);
489
0
  }
490
491
0
  g_list_free(user_info->user_info_entries);
492
0
  PURPLE_DBUS_UNREGISTER_POINTER(user_info);
493
0
  g_free(user_info);
494
0
}
495
496
GList *
497
purple_notify_user_info_get_entries(PurpleNotifyUserInfo *user_info)
498
0
{
499
0
  g_return_val_if_fail(user_info != NULL, NULL);
500
501
0
  return user_info->user_info_entries;
502
0
}
503
504
char *
505
purple_notify_user_info_get_text_with_newline(PurpleNotifyUserInfo *user_info, const char *newline)
506
0
{
507
0
  GList *l;
508
0
  GString *text;
509
510
0
  text = g_string_new("");
511
512
0
  for (l = user_info->user_info_entries; l != NULL; l = l->next) {
513
0
    PurpleNotifyUserInfoEntry *user_info_entry = l->data;
514
    /* Add a newline before a section header */
515
0
    if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
516
0
      g_string_append(text, newline);
517
518
    /* Handle the label/value pair itself */
519
    /* XXX Todo: Use a larger size for a section header? */
520
0
    if (user_info_entry->label)
521
0
      g_string_append_printf(text, "<b>%s</b>", user_info_entry->label);
522
0
    if (user_info_entry->label && user_info_entry->value)
523
0
      g_string_append(text, ": ");
524
0
    if (user_info_entry->value)
525
0
      g_string_append(text, user_info_entry->value);
526
527
    /* Display a section break as a horizontal line */
528
0
    if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK)
529
0
      g_string_append(text, "<HR>");
530
531
    /* Don't insert a new line before or after a section break; <HR> does that for us */
532
0
    if ((user_info_entry->type != PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK) &&
533
0
      (l->next && ((((PurpleNotifyUserInfoEntry *)(l->next->data))->type != PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK))))
534
0
      g_string_append(text, newline);
535
536
    /* Add an extra newline after a section header */
537
0
    if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
538
0
      g_string_append(text, newline);
539
0
  }
540
541
0
  return g_string_free(text, FALSE);
542
0
}
543
544
545
const gchar *
546
purple_notify_user_info_entry_get_label(PurpleNotifyUserInfoEntry *user_info_entry)
547
0
{
548
0
  g_return_val_if_fail(user_info_entry != NULL, NULL);
549
550
0
  return user_info_entry->label;
551
0
}
552
553
void
554
purple_notify_user_info_entry_set_label(PurpleNotifyUserInfoEntry *user_info_entry, const char *label)
555
0
{
556
0
  g_return_if_fail(user_info_entry != NULL);
557
558
0
  g_free(user_info_entry->label);
559
0
  user_info_entry->label = g_strdup(label);
560
0
}
561
562
const gchar *
563
purple_notify_user_info_entry_get_value(PurpleNotifyUserInfoEntry *user_info_entry)
564
0
{
565
0
  g_return_val_if_fail(user_info_entry != NULL, NULL);
566
567
0
  return user_info_entry->value;
568
0
}
569
570
void
571
purple_notify_user_info_entry_set_value(PurpleNotifyUserInfoEntry *user_info_entry, const char *value)
572
0
{
573
0
  g_return_if_fail(user_info_entry != NULL);
574
575
0
  g_free(user_info_entry->value);
576
0
  user_info_entry->value = g_strdup(value);
577
0
}
578
579
PurpleNotifyUserInfoEntryType
580
purple_notify_user_info_entry_get_type(PurpleNotifyUserInfoEntry *user_info_entry)
581
0
{
582
0
  g_return_val_if_fail(user_info_entry != NULL, PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR);
583
584
0
  return user_info_entry->type;
585
0
}
586
587
void
588
purple_notify_user_info_entry_set_type(PurpleNotifyUserInfoEntry *user_info_entry, PurpleNotifyUserInfoEntryType type)
589
0
{
590
0
  g_return_if_fail(user_info_entry != NULL);
591
592
0
  user_info_entry->type = type;
593
0
}
594
595
void
596
purple_notify_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
597
0
{
598
0
  PurpleNotifyUserInfoEntry *entry;
599
600
0
  entry = purple_notify_user_info_entry_new(label, value);
601
0
  user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
602
0
}
603
604
void
605
purple_notify_user_info_add_pair_plaintext(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
606
0
{
607
0
  gchar *escaped;
608
0
  PurpleNotifyUserInfoEntry *entry;
609
610
0
  escaped = g_markup_escape_text(value, -1);
611
0
  entry = purple_notify_user_info_entry_new(label, escaped);
612
0
  g_free(escaped);
613
0
  user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
614
0
}
615
616
void
617
purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
618
0
{
619
0
  PurpleNotifyUserInfoEntry *entry;
620
621
0
  entry = purple_notify_user_info_entry_new(label, value);
622
0
  user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
623
0
}
624
625
void
626
purple_notify_user_info_remove_entry(PurpleNotifyUserInfo *user_info, PurpleNotifyUserInfoEntry *entry)
627
0
{
628
0
  g_return_if_fail(user_info != NULL);
629
0
  g_return_if_fail(entry != NULL);
630
631
0
  user_info->user_info_entries = g_list_remove(user_info->user_info_entries, entry);
632
0
}
633
634
void
635
purple_notify_user_info_add_section_header(PurpleNotifyUserInfo *user_info, const char *label)
636
0
{
637
0
  PurpleNotifyUserInfoEntry *entry;
638
639
0
  entry = purple_notify_user_info_entry_new(label, NULL);
640
0
  entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER;
641
642
0
  user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
643
0
}
644
645
void
646
purple_notify_user_info_prepend_section_header(PurpleNotifyUserInfo *user_info, const char *label)
647
0
{
648
0
  PurpleNotifyUserInfoEntry *entry;
649
650
0
  entry = purple_notify_user_info_entry_new(label, NULL);
651
0
  entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER;
652
653
0
  user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
654
0
}
655
656
void
657
purple_notify_user_info_add_section_break(PurpleNotifyUserInfo *user_info)
658
0
{
659
0
  PurpleNotifyUserInfoEntry *entry;
660
661
0
  entry = purple_notify_user_info_entry_new(NULL, NULL);
662
0
  entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK;
663
664
0
  user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
665
0
}
666
667
void
668
purple_notify_user_info_prepend_section_break(PurpleNotifyUserInfo *user_info)
669
0
{
670
0
  PurpleNotifyUserInfoEntry *entry;
671
672
0
  entry = purple_notify_user_info_entry_new(NULL, NULL);
673
0
  entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK;
674
675
0
  user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
676
0
}
677
678
void
679
purple_notify_user_info_remove_last_item(PurpleNotifyUserInfo *user_info)
680
0
{
681
0
  GList *last = g_list_last(user_info->user_info_entries);
682
0
  if (last) {
683
0
    purple_notify_user_info_entry_destroy(last->data);
684
0
    user_info->user_info_entries = g_list_delete_link(user_info->user_info_entries, last);
685
0
  }
686
0
}
687
688
void *
689
purple_notify_uri(void *handle, const char *uri)
690
0
{
691
0
  PurpleNotifyUiOps *ops;
692
693
0
  g_return_val_if_fail(uri != NULL, NULL);
694
695
0
  ops = purple_notify_get_ui_ops();
696
697
0
  if (ops != NULL && ops->notify_uri != NULL) {
698
699
0
    void *ui_handle = ops->notify_uri(uri);
700
701
0
    if (ui_handle != NULL) {
702
703
0
      PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
704
0
      info->type = PURPLE_NOTIFY_URI;
705
0
      info->handle = handle;
706
0
      info->ui_handle = ui_handle;
707
708
0
      handles = g_list_append(handles, info);
709
710
0
      return info->ui_handle;
711
0
    }
712
0
  }
713
714
0
  return NULL;
715
0
}
716
717
void
718
purple_notify_close(PurpleNotifyType type, void *ui_handle)
719
0
{
720
0
  GList *l;
721
0
  PurpleNotifyUiOps *ops;
722
723
0
  g_return_if_fail(ui_handle != NULL);
724
725
0
  ops = purple_notify_get_ui_ops();
726
727
0
  for (l = handles; l != NULL; l = l->next) {
728
0
    PurpleNotifyInfo *info = l->data;
729
730
0
    if (info->ui_handle == ui_handle) {
731
0
      handles = g_list_remove(handles, info);
732
733
0
      if (ops != NULL && ops->close_notify != NULL)
734
0
        ops->close_notify(info->type, ui_handle);
735
736
0
      if (info->cb != NULL)
737
0
        info->cb(info->cb_user_data);
738
739
0
      g_free(info);
740
741
0
      break;
742
0
    }
743
0
  }
744
0
}
745
746
void
747
purple_notify_close_with_handle(void *handle)
748
0
{
749
0
  GList *l;
750
0
  PurpleNotifyUiOps *ops;
751
752
0
  g_return_if_fail(handle != NULL);
753
754
0
  ops = purple_notify_get_ui_ops();
755
756
0
  l = handles;
757
0
  while(l != NULL) {
758
0
    PurpleNotifyInfo *info = (PurpleNotifyInfo *)l->data;
759
760
0
    if(info != NULL && info->handle == handle) {
761
      /* Move to the next item before we remove our current item. */
762
0
      l = l->next;
763
764
0
      handles = g_list_remove(handles, info);
765
766
0
      if (ops != NULL && ops->close_notify != NULL)
767
0
        ops->close_notify(info->type, info->ui_handle);
768
769
0
      if (info->cb != NULL)
770
0
        info->cb(info->cb_user_data);
771
772
0
      g_free(info);
773
0
    } else {
774
0
      l = l->next;
775
0
    }
776
0
  }
777
0
}
778
779
void
780
purple_notify_set_ui_ops(PurpleNotifyUiOps *ops)
781
0
{
782
0
  notify_ui_ops = ops;
783
0
}
784
785
PurpleNotifyUiOps *
786
purple_notify_get_ui_ops(void)
787
0
{
788
0
  return notify_ui_ops;
789
0
}
790
791
void *
792
purple_notify_get_handle(void)
793
0
{
794
0
  static int handle;
795
796
0
  return &handle;
797
0
}
798
799
void
800
purple_notify_init(void)
801
0
{
802
0
  gpointer handle = purple_notify_get_handle();
803
804
0
  purple_signal_register(handle, "displaying-email-notification",
805
0
             purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER, NULL, 4,
806
0
             purple_value_new(PURPLE_TYPE_STRING),
807
0
             purple_value_new(PURPLE_TYPE_STRING),
808
0
             purple_value_new(PURPLE_TYPE_STRING),
809
0
             purple_value_new(PURPLE_TYPE_STRING));
810
811
0
  purple_signal_register(handle, "displaying-emails-notification",
812
0
             purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT, NULL, 5,
813
0
             purple_value_new(PURPLE_TYPE_POINTER),
814
0
             purple_value_new(PURPLE_TYPE_POINTER),
815
0
             purple_value_new(PURPLE_TYPE_POINTER),
816
0
             purple_value_new(PURPLE_TYPE_POINTER),
817
0
             purple_value_new(PURPLE_TYPE_UINT));
818
819
0
  purple_signal_register(handle, "displaying-userinfo",
820
0
             purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
821
0
             purple_value_new(PURPLE_TYPE_SUBTYPE,
822
0
                    PURPLE_SUBTYPE_ACCOUNT),
823
0
             purple_value_new(PURPLE_TYPE_STRING),
824
0
             purple_value_new(PURPLE_TYPE_SUBTYPE,
825
0
                    PURPLE_SUBTYPE_USERINFO));
826
0
}
827
828
void
829
purple_notify_uninit(void)
830
0
{
831
0
  purple_signals_unregister_by_instance(purple_notify_get_handle());
832
0
}