Coverage Report

Created: 2025-08-28 06:24

/src/pidgin/libpurple/roomlist.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file roomlist.c Room List 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
27
#include "internal.h"
28
29
#include "account.h"
30
#include "connection.h"
31
#include "debug.h"
32
#include "glibcompat.h"
33
#include "roomlist.h"
34
#include "server.h"
35
36
37
static PurpleRoomlistUiOps *ops = NULL;
38
39
/**************************************************************************/
40
/** @name Room List API                                                   */
41
/**************************************************************************/
42
/*@{*/
43
44
void purple_roomlist_show_with_account(PurpleAccount *account)
45
0
{
46
0
  if (ops && ops->show_with_account)
47
0
    ops->show_with_account(account);
48
0
}
49
50
PurpleRoomlist *purple_roomlist_new(PurpleAccount *account)
51
0
{
52
0
  PurpleRoomlist *list;
53
54
0
  g_return_val_if_fail(account != NULL, NULL);
55
56
0
  list = g_new0(PurpleRoomlist, 1);
57
0
  list->account = account;
58
0
  list->rooms = NULL;
59
0
  list->fields = NULL;
60
0
  list->ref = 1;
61
62
0
  if (ops && ops->create)
63
0
    ops->create(list);
64
65
0
  return list;
66
0
}
67
68
void purple_roomlist_ref(PurpleRoomlist *list)
69
0
{
70
0
  g_return_if_fail(list != NULL);
71
72
0
  list->ref++;
73
0
  purple_debug_misc("roomlist", "reffing list, ref count now %d\n", list->ref);
74
0
}
75
76
static void purple_roomlist_room_destroy(PurpleRoomlist *list, PurpleRoomlistRoom *r)
77
0
{
78
0
  GList *l, *j;
79
80
0
  for (l = list->fields, j = r->fields; l && j; l = l->next, j = j->next) {
81
0
    PurpleRoomlistField *f = l->data;
82
0
    if (f->type == PURPLE_ROOMLIST_FIELD_STRING)
83
0
      g_free(j->data);
84
0
  }
85
86
0
  g_list_free(r->fields);
87
0
  g_free(r->name);
88
0
  g_free(r);
89
0
}
90
91
static void purple_roomlist_field_destroy(PurpleRoomlistField *f)
92
0
{
93
0
  g_free(f->label);
94
0
  g_free(f->name);
95
0
  g_free(f);
96
0
}
97
98
static void purple_roomlist_destroy(PurpleRoomlist *list)
99
0
{
100
0
  GList *l;
101
102
0
  purple_debug_misc("roomlist", "destroying list %p\n", list);
103
104
0
  if (ops && ops->destroy)
105
0
    ops->destroy(list);
106
107
0
  for (l = list->rooms; l; l = l->next) {
108
0
    PurpleRoomlistRoom *r = l->data;
109
0
    purple_roomlist_room_destroy(list, r);
110
0
  }
111
0
  g_list_free(list->rooms);
112
113
0
  g_list_free_full(list->fields,
114
0
                   (GDestroyNotify)purple_roomlist_field_destroy);
115
116
0
  g_free(list);
117
0
}
118
119
void purple_roomlist_unref(PurpleRoomlist *list)
120
0
{
121
0
  g_return_if_fail(list != NULL);
122
0
  g_return_if_fail(list->ref > 0);
123
124
0
  list->ref--;
125
126
0
  purple_debug_misc("roomlist", "unreffing list, ref count now %d\n", list->ref);
127
0
  if (list->ref == 0)
128
0
    purple_roomlist_destroy(list);
129
0
}
130
131
void purple_roomlist_set_fields(PurpleRoomlist *list, GList *fields)
132
0
{
133
0
  g_return_if_fail(list != NULL);
134
135
0
  list->fields = fields;
136
137
0
  if (ops && ops->set_fields)
138
0
    ops->set_fields(list, fields);
139
0
}
140
141
void purple_roomlist_set_in_progress(PurpleRoomlist *list, gboolean in_progress)
142
0
{
143
0
  g_return_if_fail(list != NULL);
144
145
0
  list->in_progress = in_progress;
146
147
0
  if (ops && ops->in_progress)
148
0
    ops->in_progress(list, in_progress);
149
0
}
150
151
gboolean purple_roomlist_get_in_progress(PurpleRoomlist *list)
152
0
{
153
0
  g_return_val_if_fail(list != NULL, FALSE);
154
155
0
  return list->in_progress;
156
0
}
157
158
void purple_roomlist_room_add(PurpleRoomlist *list, PurpleRoomlistRoom *room)
159
0
{
160
0
  g_return_if_fail(list != NULL);
161
0
  g_return_if_fail(room != NULL);
162
163
0
  list->rooms = g_list_append(list->rooms, room);
164
165
0
  if (ops && ops->add_room)
166
0
    ops->add_room(list, room);
167
0
}
168
169
PurpleRoomlist *purple_roomlist_get_list(PurpleConnection *gc)
170
0
{
171
0
  PurplePlugin *prpl = NULL;
172
0
  PurplePluginProtocolInfo *prpl_info = NULL;
173
174
0
  g_return_val_if_fail(gc != NULL, NULL);
175
0
  g_return_val_if_fail(PURPLE_CONNECTION_IS_CONNECTED(gc), NULL);
176
177
0
  prpl = purple_connection_get_prpl(gc);
178
179
0
  if(prpl != NULL)
180
0
    prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
181
182
0
  if(prpl_info && prpl_info->roomlist_get_list)
183
0
    return prpl_info->roomlist_get_list(gc);
184
185
0
  return NULL;
186
0
}
187
188
void purple_roomlist_cancel_get_list(PurpleRoomlist *list)
189
0
{
190
0
  PurplePlugin *prpl = NULL;
191
0
  PurplePluginProtocolInfo *prpl_info = NULL;
192
0
  PurpleConnection *gc;
193
194
0
  g_return_if_fail(list != NULL);
195
196
0
  gc = purple_account_get_connection(list->account);
197
198
0
  g_return_if_fail(gc != NULL);
199
200
0
  if(gc)
201
0
    prpl = purple_connection_get_prpl(gc);
202
203
0
  if(prpl)
204
0
    prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
205
206
0
  if(prpl_info && prpl_info->roomlist_cancel)
207
0
    prpl_info->roomlist_cancel(list);
208
0
}
209
210
void purple_roomlist_expand_category(PurpleRoomlist *list, PurpleRoomlistRoom *category)
211
0
{
212
0
  PurplePlugin *prpl = NULL;
213
0
  PurplePluginProtocolInfo *prpl_info = NULL;
214
0
  PurpleConnection *gc;
215
216
0
  g_return_if_fail(list != NULL);
217
0
  g_return_if_fail(category != NULL);
218
0
  g_return_if_fail(category->type & PURPLE_ROOMLIST_ROOMTYPE_CATEGORY);
219
220
0
  gc = purple_account_get_connection(list->account);
221
0
  g_return_if_fail(gc != NULL);
222
223
0
  if(gc)
224
0
    prpl = purple_connection_get_prpl(gc);
225
226
0
  if(prpl)
227
0
    prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
228
229
0
  if(prpl_info && prpl_info->roomlist_expand_category)
230
0
    prpl_info->roomlist_expand_category(list, category);
231
0
}
232
233
GList * purple_roomlist_get_fields(PurpleRoomlist *list)
234
0
{
235
0
  return list->fields;
236
0
}
237
238
/*@}*/
239
240
/**************************************************************************/
241
/** @name Room API                                                        */
242
/**************************************************************************/
243
/*@{*/
244
245
PurpleRoomlistRoom *purple_roomlist_room_new(PurpleRoomlistRoomType type, const gchar *name,
246
                                         PurpleRoomlistRoom *parent)
247
0
{
248
0
  PurpleRoomlistRoom *room;
249
250
0
  g_return_val_if_fail(name != NULL, NULL);
251
252
0
  room = g_new0(PurpleRoomlistRoom, 1);
253
0
  room->type = type;
254
0
  room->name = g_strdup(name);
255
0
  room->parent = parent;
256
257
0
  return room;
258
0
}
259
260
void purple_roomlist_room_add_field(PurpleRoomlist *list, PurpleRoomlistRoom *room, gconstpointer field)
261
0
{
262
0
  PurpleRoomlistField *f;
263
264
0
  g_return_if_fail(list != NULL);
265
0
  g_return_if_fail(room != NULL);
266
0
  g_return_if_fail(list->fields != NULL);
267
268
  /* If this is the first call for this room, grab the first field in
269
   * the Roomlist's fields.  Otherwise, grab the field that is one
270
   * more than the number of fields already present for the room.
271
         * (This works because g_list_nth_data() is zero-indexed and
272
         * g_list_length() is one-indexed.) */
273
0
  if (!room->fields)
274
0
    f = list->fields->data;
275
0
  else
276
0
    f = g_list_nth_data(list->fields, g_list_length(room->fields));
277
278
0
  g_return_if_fail(f != NULL);
279
280
0
  switch(f->type) {
281
0
    case PURPLE_ROOMLIST_FIELD_STRING:
282
0
      room->fields = g_list_append(room->fields, g_strdup(field));
283
0
      break;
284
0
    case PURPLE_ROOMLIST_FIELD_BOOL:
285
0
    case PURPLE_ROOMLIST_FIELD_INT:
286
0
      room->fields = g_list_append(room->fields, GINT_TO_POINTER(field));
287
0
      break;
288
0
  }
289
0
}
290
291
void purple_roomlist_room_join(PurpleRoomlist *list, PurpleRoomlistRoom *room)
292
0
{
293
0
  GHashTable *components;
294
0
  GList *l, *j;
295
0
  PurpleConnection *gc;
296
297
0
  g_return_if_fail(list != NULL);
298
0
  g_return_if_fail(room != NULL);
299
300
0
  gc = purple_account_get_connection(list->account);
301
0
  if (!gc)
302
0
    return;
303
304
0
  components = g_hash_table_new(g_str_hash, g_str_equal);
305
306
0
  g_hash_table_replace(components, "name", room->name);
307
0
  for (l = list->fields, j = room->fields; l && j; l = l->next, j = j->next) {
308
0
    PurpleRoomlistField *f = l->data;
309
310
0
    g_hash_table_replace(components, f->name, j->data);
311
0
  }
312
313
0
  serv_join_chat(gc, components);
314
315
0
  g_hash_table_destroy(components);
316
0
}
317
318
PurpleRoomlistRoomType purple_roomlist_room_get_type(PurpleRoomlistRoom *room)
319
0
{
320
0
  return room->type;
321
0
}
322
323
const char * purple_roomlist_room_get_name(PurpleRoomlistRoom *room)
324
0
{
325
0
  return room->name;
326
0
}
327
328
PurpleRoomlistRoom * purple_roomlist_room_get_parent(PurpleRoomlistRoom *room)
329
0
{
330
0
  return room->parent;
331
0
}
332
333
GList * purple_roomlist_room_get_fields(PurpleRoomlistRoom *room)
334
0
{
335
0
  return room->fields;
336
0
}
337
338
/*@}*/
339
340
/**************************************************************************/
341
/** @name Room Field API                                                  */
342
/**************************************************************************/
343
/*@{*/
344
345
PurpleRoomlistField *purple_roomlist_field_new(PurpleRoomlistFieldType type,
346
                                           const gchar *label, const gchar *name,
347
                                           gboolean hidden)
348
0
{
349
0
  PurpleRoomlistField *f;
350
351
0
  g_return_val_if_fail(label != NULL, NULL);
352
0
  g_return_val_if_fail(name != NULL, NULL);
353
354
0
  f = g_new0(PurpleRoomlistField, 1);
355
356
0
  f->type = type;
357
0
  f->label = g_strdup(label);
358
0
  f->name = g_strdup(name);
359
0
  f->hidden = hidden;
360
361
0
  return f;
362
0
}
363
364
PurpleRoomlistFieldType purple_roomlist_field_get_type(PurpleRoomlistField *field)
365
0
{
366
0
  return field->type;
367
0
}
368
369
const char * purple_roomlist_field_get_label(PurpleRoomlistField *field)
370
0
{
371
0
  return field->label;
372
0
}
373
374
gboolean purple_roomlist_field_get_hidden(PurpleRoomlistField *field)
375
0
{
376
0
  return field->hidden;
377
0
}
378
379
/*@}*/
380
381
/**************************************************************************/
382
/** @name UI Registration Functions                                       */
383
/**************************************************************************/
384
/*@{*/
385
386
387
void purple_roomlist_set_ui_ops(PurpleRoomlistUiOps *ui_ops)
388
0
{
389
0
  ops = ui_ops;
390
0
}
391
392
PurpleRoomlistUiOps *purple_roomlist_get_ui_ops(void)
393
0
{
394
0
  return ops;
395
0
}
396
397
/*@}*/