Mercurial > pidgin.yaz
annotate src/blist.c @ 5411:2c4188300aba
[gaim-migrate @ 5787]
This fixes an i18n thing, I think.
I changed some stuff in oscar.c to use _() instead of calling gettext
directly. That's ok, right? I like the macro better.
I also fixed a compile warning or two. If that function declaration
isn't supposed to be there, feel free to move it, or remove it, or
lemme know and I'll do it.
Viva 0.63!
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sat, 17 May 2003 05:41:18 +0000 |
parents | 08a90a9e28e4 |
children | a2f26666de42 |
rev | line source |
---|---|
5228 | 1 /* |
2 * gaim | |
3 * | |
4 * Copyright (C) 2003, Sean Egan <sean.egan@binghamton.edu> | |
5 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 * | |
21 */ | |
22 | |
23 #ifdef HAVE_CONFIG_H | |
24 #include <config.h> | |
25 #endif | |
26 #include <string.h> | |
27 #include <stdlib.h> | |
28 #include <sys/types.h> | |
29 #include <sys/stat.h> | |
30 #ifndef _WIN32 | |
31 #include <unistd.h> | |
32 #else | |
33 #include <direct.h> | |
34 #endif | |
35 #include <ctype.h> | |
36 #include "gaim.h" | |
37 #include "prpl.h" | |
38 #include "blist.h" | |
39 | |
40 #ifdef _WIN32 | |
41 #include "win32dep.h" | |
42 #endif | |
43 | |
44 #define PATHSIZE 1024 | |
45 | |
46 struct gaim_buddy_list *gaimbuddylist = NULL; | |
47 static struct gaim_blist_ui_ops *blist_ui_ops = NULL; | |
48 | |
49 /***************************************************************************** | |
50 * Private Utility functions * | |
51 *****************************************************************************/ | |
52 static GaimBlistNode *gaim_blist_get_last_sibling(GaimBlistNode *node) | |
53 { | |
54 GaimBlistNode *n = node; | |
55 if (!n) | |
56 return NULL; | |
57 while (n->next) | |
58 n = n->next; | |
59 return n; | |
60 } | |
61 static GaimBlistNode *gaim_blist_get_last_child(GaimBlistNode *node) | |
62 { | |
63 if (!node) | |
64 return NULL; | |
65 return gaim_blist_get_last_sibling(node->child); | |
66 } | |
67 | |
5247 | 68 struct _gaim_hbuddy { |
69 char *name; | |
70 struct gaim_account *account; | |
71 }; | |
72 | |
73 static guint _gaim_blist_hbuddy_hash (struct _gaim_hbuddy *hb) | |
74 { | |
75 return g_str_hash(hb->name); | |
76 } | |
77 | |
78 static guint _gaim_blist_hbuddy_equal (struct _gaim_hbuddy *hb1, struct _gaim_hbuddy *hb2) | |
79 { | |
80 return ((!strcmp(hb1->name, hb2->name)) && hb1->account == hb2->account); | |
81 } | |
82 | |
5228 | 83 /***************************************************************************** |
84 * Public API functions * | |
85 *****************************************************************************/ | |
86 | |
87 struct gaim_buddy_list *gaim_blist_new() | |
88 { | |
89 struct gaim_buddy_list *gbl = g_new0(struct gaim_buddy_list, 1); | |
90 | |
91 gbl->ui_ops = gaim_get_blist_ui_ops(); | |
92 | |
5247 | 93 gbl->buddies = g_hash_table_new ((GHashFunc)_gaim_blist_hbuddy_hash, |
94 (GEqualFunc)_gaim_blist_hbuddy_equal); | |
95 | |
5228 | 96 if (gbl->ui_ops != NULL && gbl->ui_ops->new_list != NULL) |
97 gbl->ui_ops->new_list(gbl); | |
98 | |
99 return gbl; | |
100 } | |
101 | |
102 void | |
103 gaim_set_blist(struct gaim_buddy_list *list) | |
104 { | |
105 gaimbuddylist = list; | |
106 } | |
107 | |
108 struct gaim_buddy_list * | |
109 gaim_get_blist(void) | |
110 { | |
111 return gaimbuddylist; | |
112 } | |
113 | |
114 void gaim_blist_show () | |
115 { | |
116 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
117 if (ops) | |
118 ops->show(gaimbuddylist); | |
119 } | |
120 | |
121 void gaim_blist_destroy() | |
122 { | |
123 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
124 if (ops) | |
125 ops->destroy(gaimbuddylist); | |
126 } | |
127 | |
128 void gaim_blist_set_visible (gboolean show) | |
129 { | |
130 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
131 if (ops) | |
132 ops->set_visible(gaimbuddylist, show); | |
133 } | |
134 | |
135 void gaim_blist_update_buddy_status (struct buddy *buddy, int status) | |
136 { | |
5266
b3a03b86b09b
[gaim-migrate @ 5638]
Christian Hammond <chipx86@chipx86.com>
parents:
5259
diff
changeset
|
137 struct gaim_blist_ui_ops *ops; |
b3a03b86b09b
[gaim-migrate @ 5638]
Christian Hammond <chipx86@chipx86.com>
parents:
5259
diff
changeset
|
138 |
b3a03b86b09b
[gaim-migrate @ 5638]
Christian Hammond <chipx86@chipx86.com>
parents:
5259
diff
changeset
|
139 if (buddy->uc == status) |
b3a03b86b09b
[gaim-migrate @ 5638]
Christian Hammond <chipx86@chipx86.com>
parents:
5259
diff
changeset
|
140 return; |
b3a03b86b09b
[gaim-migrate @ 5638]
Christian Hammond <chipx86@chipx86.com>
parents:
5259
diff
changeset
|
141 |
b3a03b86b09b
[gaim-migrate @ 5638]
Christian Hammond <chipx86@chipx86.com>
parents:
5259
diff
changeset
|
142 ops = gaimbuddylist->ui_ops; |
5228 | 143 |
5305 | 144 if((status & UC_UNAVAILABLE) != (buddy->uc & UC_UNAVAILABLE)) { |
145 if(status & UC_UNAVAILABLE) | |
146 gaim_event_broadcast(event_buddy_away, buddy->account->gc, buddy->name); | |
147 else | |
148 gaim_event_broadcast(event_buddy_back, buddy->account->gc, buddy->name); | |
149 } | |
5228 | 150 |
5305 | 151 buddy->uc = status; |
5228 | 152 if (ops) |
153 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
154 } | |
155 | |
156 static gboolean presence_update_timeout_cb(struct buddy *buddy) { | |
157 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
158 | |
159 if(buddy->present == GAIM_BUDDY_SIGNING_ON) { | |
160 buddy->present = GAIM_BUDDY_ONLINE; | |
161 gaim_event_broadcast(event_buddy_signon, buddy->account->gc, buddy->name); | |
162 } else if(buddy->present == GAIM_BUDDY_SIGNING_OFF) { | |
163 buddy->present = GAIM_BUDDY_OFFLINE; | |
164 } | |
165 | |
166 buddy->timer = 0; | |
167 | |
168 if (ops) | |
169 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
170 | |
171 return FALSE; | |
172 } | |
173 | |
174 void gaim_blist_update_buddy_presence(struct buddy *buddy, int presence) { | |
175 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
176 gboolean do_timer = FALSE; | |
177 | |
178 if (!GAIM_BUDDY_IS_ONLINE(buddy) && presence) { | |
179 buddy->present = GAIM_BUDDY_SIGNING_ON; | |
180 gaim_event_broadcast(event_buddy_signon, buddy->account->gc, buddy->name); | |
181 do_timer = TRUE; | |
5277 | 182 ((struct group *)((GaimBlistNode *)buddy)->parent)->online++; |
5228 | 183 } else if(GAIM_BUDDY_IS_ONLINE(buddy) && !presence) { |
184 buddy->present = GAIM_BUDDY_SIGNING_OFF; | |
185 gaim_event_broadcast(event_buddy_signoff, buddy->account->gc, buddy->name); | |
186 do_timer = TRUE; | |
5394 | 187 ((struct group *)((GaimBlistNode *)buddy)->parent)->online--; |
5228 | 188 } |
189 | |
190 if(do_timer) { | |
191 if(buddy->timer > 0) | |
192 g_source_remove(buddy->timer); | |
193 buddy->timer = g_timeout_add(10000, (GSourceFunc)presence_update_timeout_cb, buddy); | |
194 } | |
195 | |
196 if (ops) | |
197 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
198 } | |
199 | |
200 | |
201 void gaim_blist_update_buddy_idle (struct buddy *buddy, int idle) | |
202 { | |
203 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
204 buddy->idle = idle; | |
205 if (ops) | |
206 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
207 } | |
208 void gaim_blist_update_buddy_evil (struct buddy *buddy, int warning) | |
209 { | |
210 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
211 buddy->evil = warning; | |
212 if (ops) | |
213 ops->update(gaimbuddylist,(GaimBlistNode*)buddy); | |
214 } | |
215 void gaim_blist_update_buddy_icon(struct buddy *buddy) { | |
216 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
217 if(ops) | |
218 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
219 } | |
220 void gaim_blist_rename_buddy (struct buddy *buddy, const char *name) | |
221 { | |
222 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
223 g_free(buddy->name); | |
224 buddy->name = g_strdup(name); | |
225 if (ops) | |
226 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
227 } | |
5234 | 228 |
229 void gaim_blist_alias_chat(struct chat *chat, const char *alias) | |
230 { | |
231 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
232 | |
5237 | 233 g_free(chat->alias); |
5234 | 234 |
5237 | 235 if(alias && strlen(alias)) |
236 chat->alias = g_strdup(alias); | |
237 else | |
238 chat->alias = NULL; | |
239 | |
5234 | 240 if(ops) |
241 ops->update(gaimbuddylist, (GaimBlistNode*)chat); | |
242 } | |
243 | |
5228 | 244 void gaim_blist_alias_buddy (struct buddy *buddy, const char *alias) |
245 { | |
246 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
247 struct gaim_conversation *conv; | |
248 | |
249 g_free(buddy->alias); | |
250 | |
251 if(alias && strlen(alias)) | |
252 buddy->alias = g_strdup(alias); | |
253 else | |
254 buddy->alias = NULL; | |
255 | |
256 if (ops) | |
257 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
258 | |
259 conv = gaim_find_conversation_with_account(buddy->name, buddy->account); | |
260 | |
261 if (conv) | |
262 gaim_conversation_autoset_title(conv); | |
263 } | |
264 | |
265 void gaim_blist_rename_group(struct group *group, const char *name) | |
266 { | |
267 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
5346 | 268 struct group *dest_group; |
269 GaimBlistNode *prev, *child, *next; | |
270 GSList *accts; | |
271 | |
272 if(!name || !strlen(name) || !strcmp(name, group->name)) { | |
273 /* nothing to do here */ | |
274 return; | |
275 } else if((dest_group = gaim_find_group(name))) { | |
276 /* here we're merging two groups */ | |
277 prev = gaim_blist_get_last_child((GaimBlistNode*)dest_group); | |
278 child = ((GaimBlistNode*)group)->child; | |
279 | |
280 while(child) | |
281 { | |
282 next = child->next; | |
283 if(GAIM_BLIST_NODE_IS_BUDDY(child)) { | |
284 gaim_blist_add_buddy((struct buddy *)child, dest_group, prev); | |
285 prev = child; | |
286 } else if(GAIM_BLIST_NODE_IS_CHAT(child)) { | |
287 gaim_blist_add_chat((struct chat *)child, dest_group, prev); | |
288 prev = child; | |
289 } else { | |
290 gaim_debug(GAIM_DEBUG_ERROR, "blist", | |
291 "Unknown child type in group %s\n", group->name); | |
292 } | |
293 child = next; | |
294 } | |
295 for (accts = gaim_group_get_accounts(group); accts; accts = g_slist_remove(accts, accts->data)) { | |
296 struct gaim_account *account = accts->data; | |
297 serv_rename_group(account->gc, group, name); | |
298 } | |
299 gaim_blist_remove_group(group); | |
300 } else { | |
301 /* a simple rename */ | |
302 for (accts = gaim_group_get_accounts(group); accts; accts = g_slist_remove(accts, accts->data)) { | |
303 struct gaim_account *account = accts->data; | |
304 serv_rename_group(account->gc, group, name); | |
305 } | |
306 g_free(group->name); | |
307 group->name = g_strdup(name); | |
308 if (ops) | |
309 ops->update(gaimbuddylist, (GaimBlistNode*)group); | |
310 } | |
5228 | 311 } |
5234 | 312 |
313 struct chat *gaim_chat_new(struct gaim_account *account, const char *alias, GHashTable *components) | |
314 { | |
315 struct chat *chat; | |
316 struct gaim_blist_ui_ops *ops; | |
317 | |
5237 | 318 if(!components) |
5234 | 319 return NULL; |
320 | |
321 chat = g_new0(struct chat, 1); | |
322 chat->account = account; | |
5237 | 323 if(alias && strlen(alias)) |
324 chat->alias = g_strdup(alias); | |
5234 | 325 chat->components = components; |
326 | |
327 ((GaimBlistNode*)chat)->type = GAIM_BLIST_CHAT_NODE; | |
328 | |
329 ops = gaim_get_blist_ui_ops(); | |
330 | |
331 if (ops != NULL && ops->new_node != NULL) | |
332 ops->new_node((GaimBlistNode *)chat); | |
333 | |
334 return chat; | |
335 } | |
336 | |
5228 | 337 struct buddy *gaim_buddy_new(struct gaim_account *account, const char *screenname, const char *alias) |
338 { | |
339 struct buddy *b; | |
340 struct gaim_blist_ui_ops *ops; | |
341 | |
342 b = g_new0(struct buddy, 1); | |
343 b->account = account; | |
344 b->name = g_strdup(screenname); | |
345 b->alias = g_strdup(alias); | |
346 b->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
347 ((GaimBlistNode*)b)->type = GAIM_BLIST_BUDDY_NODE; | |
348 | |
349 ops = gaim_get_blist_ui_ops(); | |
350 | |
351 if (ops != NULL && ops->new_node != NULL) | |
352 ops->new_node((GaimBlistNode *)b); | |
353 | |
354 return b; | |
355 } | |
5234 | 356 void gaim_blist_add_chat(struct chat *chat, struct group *group, GaimBlistNode *node) |
357 { | |
358 GaimBlistNode *n = node, *cnode = (GaimBlistNode*)chat; | |
359 struct group *g = group; | |
360 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
361 gboolean save = FALSE; | |
362 | |
363 if (!n) { | |
364 if (!g) { | |
365 g = gaim_group_new(_("Chats")); | |
366 gaim_blist_add_group(g, NULL); | |
367 } | |
368 n = gaim_blist_get_last_child((GaimBlistNode*)g); | |
369 } else { | |
370 g = (struct group*)n->parent; | |
371 } | |
372 | |
373 /* if we're moving to overtop of ourselves, do nothing */ | |
374 if(cnode == n) | |
375 return; | |
376 | |
377 if (cnode->parent) { | |
378 /* This chat was already in the list and is | |
379 * being moved. | |
380 */ | |
5277 | 381 ((struct group *)cnode->parent)->totalsize--; |
5287 | 382 if (chat->account->gc) { |
383 ((struct group *)cnode->parent)->online--; | |
5277 | 384 ((struct group *)cnode->parent)->currentsize--; |
5287 | 385 } |
5234 | 386 if(cnode->next) |
387 cnode->next->prev = cnode->prev; | |
388 if(cnode->prev) | |
389 cnode->prev->next = cnode->next; | |
390 if(cnode->parent->child == cnode) | |
391 cnode->parent->child = cnode->next; | |
392 | |
393 ops->remove(gaimbuddylist, cnode); | |
394 | |
395 save = TRUE; | |
396 } | |
397 | |
398 if (n) { | |
399 if(n->next) | |
400 n->next->prev = cnode; | |
401 cnode->next = n->next; | |
402 cnode->prev = n; | |
403 cnode->parent = n->parent; | |
404 n->next = cnode; | |
5277 | 405 ((struct group *)n->parent)->totalsize++; |
5287 | 406 if (chat->account->gc) { |
407 ((struct group *)n->parent)->online++; | |
5277 | 408 ((struct group *)n->parent)->currentsize++; |
5287 | 409 } |
5234 | 410 } else { |
411 ((GaimBlistNode*)g)->child = cnode; | |
412 cnode->next = cnode->prev = NULL; | |
413 cnode->parent = (GaimBlistNode*)g; | |
5277 | 414 g->totalsize++; |
5287 | 415 if (chat->account->gc) { |
416 g->online++; | |
5277 | 417 g->currentsize++; |
5287 | 418 } |
5234 | 419 } |
420 | |
421 if (ops) | |
422 ops->update(gaimbuddylist, (GaimBlistNode*)cnode); | |
423 if (save) | |
424 gaim_blist_save(); | |
425 } | |
426 | |
5228 | 427 void gaim_blist_add_buddy (struct buddy *buddy, struct group *group, GaimBlistNode *node) |
428 { | |
429 GaimBlistNode *n = node, *bnode = (GaimBlistNode*)buddy; | |
430 struct group *g = group; | |
431 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
5247 | 432 struct _gaim_hbuddy *hb; |
5228 | 433 gboolean save = FALSE; |
434 | |
435 if (!n) { | |
436 if (!g) { | |
437 g = gaim_group_new(_("Buddies")); | |
438 gaim_blist_add_group(g, NULL); | |
439 } | |
440 n = gaim_blist_get_last_child((GaimBlistNode*)g); | |
441 } else { | |
442 g = (struct group*)n->parent; | |
443 } | |
444 | |
445 /* if we're moving to overtop of ourselves, do nothing */ | |
446 if(bnode == n) | |
447 return; | |
448 | |
449 if (bnode->parent) { | |
450 /* This buddy was already in the list and is | |
451 * being moved. | |
452 */ | |
5394 | 453 ((struct group *)bnode->parent)->totalsize--; |
454 if (buddy->account->gc) | |
5277 | 455 ((struct group *)bnode->parent)->currentsize--; |
5394 | 456 if (GAIM_BUDDY_IS_ONLINE(buddy)) |
5313 | 457 ((struct group *)bnode->parent)->online--; |
5277 | 458 |
5228 | 459 if(bnode->next) |
460 bnode->next->prev = bnode->prev; | |
461 if(bnode->prev) | |
462 bnode->prev->next = bnode->next; | |
463 if(bnode->parent->child == bnode) | |
464 bnode->parent->child = bnode->next; | |
465 | |
466 ops->remove(gaimbuddylist, bnode); | |
467 | |
5277 | 468 if (bnode->parent != ((GaimBlistNode*)g)) { |
5228 | 469 serv_move_buddy(buddy, (struct group*)bnode->parent, g); |
5277 | 470 } |
5228 | 471 save = TRUE; |
472 } | |
473 | |
474 if (n) { | |
475 if(n->next) | |
476 n->next->prev = (GaimBlistNode*)buddy; | |
477 ((GaimBlistNode*)buddy)->next = n->next; | |
478 ((GaimBlistNode*)buddy)->prev = n; | |
479 ((GaimBlistNode*)buddy)->parent = n->parent; | |
480 n->next = (GaimBlistNode*)buddy; | |
5277 | 481 ((struct group *)n->parent)->totalsize++; |
482 if (buddy->account->gc) | |
483 ((struct group *)n->parent)->currentsize++; | |
5394 | 484 if (GAIM_BUDDY_IS_ONLINE(buddy)) |
5313 | 485 ((struct group *)n->parent)->online++; |
5228 | 486 } else { |
487 ((GaimBlistNode*)g)->child = (GaimBlistNode*)buddy; | |
488 ((GaimBlistNode*)buddy)->next = NULL; | |
489 ((GaimBlistNode*)buddy)->prev = NULL; | |
490 ((GaimBlistNode*)buddy)->parent = (GaimBlistNode*)g; | |
5277 | 491 g->totalsize++; |
492 if (buddy->account->gc) | |
493 g->currentsize++; | |
5394 | 494 if (GAIM_BUDDY_IS_ONLINE(buddy)) |
5313 | 495 g->online++; |
5228 | 496 } |
497 | |
5247 | 498 hb = g_malloc(sizeof(struct _gaim_hbuddy)); |
499 hb->name = g_strdup(normalize(buddy->name)); | |
500 hb->account = buddy->account; | |
501 | |
502 if (g_hash_table_lookup(gaimbuddylist->buddies, (gpointer)hb)) { | |
503 /* This guy already exists */ | |
504 g_free(hb->name); | |
505 g_free(hb); | |
506 } else { | |
507 g_hash_table_insert(gaimbuddylist->buddies, (gpointer)hb, (gpointer)buddy); | |
508 } | |
509 | |
5228 | 510 if (ops) |
511 ops->update(gaimbuddylist, (GaimBlistNode*)buddy); | |
512 if (save) | |
513 gaim_blist_save(); | |
514 } | |
515 | |
516 struct group *gaim_group_new(const char *name) | |
517 { | |
518 struct group *g = gaim_find_group(name); | |
519 | |
520 if (!g) { | |
521 struct gaim_blist_ui_ops *ops; | |
522 g= g_new0(struct group, 1); | |
523 g->name = g_strdup(name); | |
5277 | 524 g->totalsize = 0; |
525 g->currentsize = 0; | |
526 g->online = 0; | |
5228 | 527 g->settings = g_hash_table_new_full(g_str_hash, g_str_equal, |
528 g_free, g_free); | |
529 ((GaimBlistNode*)g)->type = GAIM_BLIST_GROUP_NODE; | |
530 | |
531 ops = gaim_get_blist_ui_ops(); | |
532 | |
533 if (ops != NULL && ops->new_node != NULL) | |
534 ops->new_node((GaimBlistNode *)g); | |
535 | |
536 } | |
537 return g; | |
538 } | |
539 | |
540 void gaim_blist_add_group (struct group *group, GaimBlistNode *node) | |
541 { | |
542 struct gaim_blist_ui_ops *ops; | |
543 GaimBlistNode *gnode = (GaimBlistNode*)group; | |
544 gboolean save = FALSE; | |
545 | |
546 if (!gaimbuddylist) | |
547 gaimbuddylist = gaim_blist_new(); | |
548 ops = gaimbuddylist->ui_ops; | |
549 | |
550 if (!gaimbuddylist->root) { | |
551 gaimbuddylist->root = gnode; | |
552 return; | |
553 } | |
554 | |
555 if (!node) | |
556 node = gaim_blist_get_last_sibling(gaimbuddylist->root); | |
557 | |
558 /* if we're moving to overtop of ourselves, do nothing */ | |
559 if(gnode == node) | |
560 return; | |
561 | |
562 if (gaim_find_group(group->name)) { | |
563 /* This is just being moved */ | |
564 | |
565 ops->remove(gaimbuddylist, (GaimBlistNode*)group); | |
566 | |
567 if(gnode == gaimbuddylist->root) | |
568 gaimbuddylist->root = gnode->next; | |
569 if(gnode->prev) | |
570 gnode->prev->next = gnode->next; | |
571 if(gnode->next) | |
572 gnode->next->prev = gnode->prev; | |
573 | |
574 save = TRUE; | |
575 } | |
576 | |
577 gnode->next = node->next; | |
578 gnode->prev = node; | |
579 if(node->next) | |
580 node->next->prev = gnode; | |
581 node->next = gnode; | |
582 | |
583 if (ops) { | |
584 ops->update(gaimbuddylist, gnode); | |
585 for(node = gnode->child; node; node = node->next) | |
586 ops->update(gaimbuddylist, node); | |
587 } | |
588 if (save) | |
589 gaim_blist_save(); | |
590 } | |
591 | |
592 void gaim_blist_remove_buddy (struct buddy *buddy) | |
593 { | |
594 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
595 | |
596 GaimBlistNode *gnode, *node = (GaimBlistNode*)buddy; | |
597 struct group *group; | |
5247 | 598 struct _gaim_hbuddy hb, *key; |
599 struct buddy *val; | |
5228 | 600 |
601 gnode = node->parent; | |
602 group = (struct group *)gnode; | |
603 | |
604 if(gnode->child == node) | |
605 gnode->child = node->next; | |
606 if (node->prev) | |
607 node->prev->next = node->next; | |
608 if (node->next) | |
609 node->next->prev = node->prev; | |
5394 | 610 group->totalsize--; |
611 if (buddy->account->gc) | |
5277 | 612 group->currentsize--; |
5394 | 613 if (GAIM_BUDDY_IS_ONLINE(buddy)) |
614 group->online--; | |
5228 | 615 |
5247 | 616 hb.name = normalize(buddy->name); |
617 hb.account = buddy->account; | |
618 if (g_hash_table_lookup_extended(gaimbuddylist->buddies, &hb, (gpointer *)&key, (gpointer *)&val)) { | |
619 g_hash_table_remove(gaimbuddylist->buddies, &hb); | |
620 g_free(key->name); | |
621 g_free(key); | |
622 } | |
623 | |
5292 | 624 if(buddy->timer > 0) |
625 g_source_remove(buddy->timer); | |
626 | |
5228 | 627 ops->remove(gaimbuddylist, node); |
628 g_hash_table_destroy(buddy->settings); | |
629 g_free(buddy->name); | |
630 g_free(buddy->alias); | |
631 g_free(buddy); | |
632 } | |
633 | |
5234 | 634 void gaim_blist_remove_chat (struct chat *chat) |
635 { | |
636 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
637 | |
638 GaimBlistNode *gnode, *node = (GaimBlistNode*)chat; | |
639 struct group *group; | |
640 | |
641 gnode = node->parent; | |
642 group = (struct group *)gnode; | |
643 | |
644 if(gnode->child == node) | |
645 gnode->child = node->next; | |
646 if (node->prev) | |
647 node->prev->next = node->next; | |
648 if (node->next) | |
649 node->next->prev = node->prev; | |
5277 | 650 group->totalsize--; |
5394 | 651 if (chat->account->gc) { |
5277 | 652 group->currentsize--; |
5394 | 653 group->online--; |
654 } | |
5234 | 655 |
656 ops->remove(gaimbuddylist, node); | |
657 g_hash_table_destroy(chat->components); | |
658 g_free(chat->alias); | |
659 g_free(chat); | |
660 } | |
661 | |
5228 | 662 void gaim_blist_remove_group (struct group *group) |
663 { | |
664 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
665 GaimBlistNode *node = (GaimBlistNode*)group; | |
666 | |
667 if(node->child) { | |
668 char *buf; | |
669 int count = 0; | |
670 GaimBlistNode *child = node->child; | |
671 | |
672 while(child) { | |
673 count++; | |
674 child = child->next; | |
675 } | |
676 | |
677 buf = g_strdup_printf(_("%d buddies from group %s were not " | |
678 "removed because their accounts were not logged in. These " | |
679 "buddies, and the group were not removed.\n"), | |
680 count, group->name); | |
681 do_error_dialog(_("Group Not Removed"), buf, GAIM_ERROR); | |
682 g_free(buf); | |
683 return; | |
684 } | |
685 | |
686 if(gaimbuddylist->root == node) | |
687 gaimbuddylist->root = node->next; | |
688 if (node->prev) | |
689 node->prev->next = node->next; | |
690 if (node->next) | |
691 node->next->prev = node->prev; | |
692 | |
693 ops->remove(gaimbuddylist, node); | |
694 g_free(group->name); | |
695 g_free(group); | |
696 } | |
697 | |
698 char *gaim_get_buddy_alias_only(struct buddy *b) { | |
699 if(!b) | |
700 return NULL; | |
701 if(b->alias && b->alias[0]) | |
702 return b->alias; | |
703 else if((misc_options & OPT_MISC_USE_SERVER_ALIAS) && b->server_alias) | |
704 return b->server_alias; | |
705 return NULL; | |
706 } | |
707 | |
708 char * gaim_get_buddy_alias (struct buddy *buddy) | |
709 { | |
710 char *ret = gaim_get_buddy_alias_only(buddy); | |
711 if(!ret) | |
712 return buddy ? buddy->name : _("Unknown"); | |
713 return ret; | |
714 | |
715 } | |
716 | |
717 struct buddy *gaim_find_buddy(struct gaim_account *account, const char *name) | |
718 { | |
5247 | 719 struct buddy *buddy; |
720 struct _gaim_hbuddy hb; | |
5228 | 721 |
722 if (!gaimbuddylist) | |
723 return NULL; | |
724 | |
5247 | 725 hb.name = normalize(name); |
726 hb.account = account; | |
727 buddy = g_hash_table_lookup(gaimbuddylist->buddies, &hb); | |
728 | |
729 return buddy; | |
5228 | 730 } |
731 | |
732 struct group *gaim_find_group(const char *name) | |
733 { | |
734 GaimBlistNode *node; | |
735 if (!gaimbuddylist) | |
736 return NULL; | |
737 node = gaimbuddylist->root; | |
738 while(node) { | |
739 if (!strcmp(((struct group*)node)->name, name)) | |
740 return (struct group*)node; | |
741 node = node->next; | |
742 } | |
743 return NULL; | |
744 } | |
745 struct group *gaim_find_buddys_group(struct buddy *buddy) | |
746 { | |
747 if (!buddy) | |
748 return NULL; | |
749 return (struct group*)(((GaimBlistNode*)buddy)->parent); | |
750 } | |
751 | |
752 GSList *gaim_group_get_accounts(struct group *g) | |
753 { | |
754 GSList *l = NULL; | |
755 GaimBlistNode *child = ((GaimBlistNode *)g)->child; | |
756 | |
757 while (child) { | |
758 if (!g_slist_find(l, ((struct buddy*)child)->account)) | |
759 l = g_slist_append(l, ((struct buddy*)child)->account); | |
760 child = child->next; | |
761 } | |
762 return l; | |
763 } | |
764 | |
5234 | 765 void gaim_blist_add_account(struct gaim_account *account) |
766 { | |
767 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
768 GaimBlistNode *group, *buddy; | |
769 | |
770 if(!gaimbuddylist) | |
771 return; | |
772 | |
773 for(group = gaimbuddylist->root; group; group = group->next) { | |
774 if(!GAIM_BLIST_NODE_IS_GROUP(group)) | |
775 continue; | |
776 for(buddy = group->child; buddy; buddy = buddy->next) { | |
777 if(GAIM_BLIST_NODE_IS_BUDDY(buddy)) { | |
778 if (account == ((struct buddy*)buddy)->account) { | |
5277 | 779 ((struct group *)group)->currentsize++; |
5234 | 780 if(ops) |
781 ops->update(gaimbuddylist, buddy); | |
782 } | |
783 } else if(GAIM_BLIST_NODE_IS_CHAT(buddy)) { | |
784 if (account == ((struct chat*)buddy)->account) { | |
5287 | 785 ((struct group *)group)->online++; |
5277 | 786 ((struct group *)group)->currentsize++; |
5234 | 787 if(ops) |
788 ops->update(gaimbuddylist, buddy); | |
789 } | |
790 } | |
791 } | |
792 } | |
793 } | |
794 | |
5228 | 795 void gaim_blist_remove_account(struct gaim_account *account) |
796 { | |
797 struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops; | |
5234 | 798 GaimBlistNode *group, *buddy; |
799 | |
5228 | 800 if (!gaimbuddylist) |
801 return; | |
5234 | 802 |
803 for(group = gaimbuddylist->root; group; group = group->next) { | |
804 if(!GAIM_BLIST_NODE_IS_GROUP(group)) | |
805 continue; | |
806 for(buddy = group->child; buddy; buddy = buddy->next) { | |
807 if(GAIM_BLIST_NODE_IS_BUDDY(buddy)) { | |
808 if (account == ((struct buddy*)buddy)->account) { | |
5394 | 809 if (GAIM_BUDDY_IS_ONLINE((struct buddy*)buddy)) |
5277 | 810 ((struct group *)group)->online--; |
5234 | 811 ((struct buddy*)buddy)->present = GAIM_BUDDY_OFFLINE; |
5394 | 812 ((struct group *)group)->currentsize--; |
5234 | 813 if(ops) |
814 ops->remove(gaimbuddylist, buddy); | |
815 } | |
816 } else if(GAIM_BLIST_NODE_IS_CHAT(buddy)) { | |
817 if (account == ((struct chat*)buddy)->account) { | |
5277 | 818 ((struct group *)group)->online--; |
819 ((struct group *)group)->currentsize--; | |
5234 | 820 if(ops) |
821 ops->remove(gaimbuddylist, buddy); | |
822 } | |
5228 | 823 } |
824 } | |
825 } | |
826 } | |
827 | |
828 void parse_toc_buddy_list(struct gaim_account *account, char *config) | |
829 { | |
830 char *c; | |
831 char current[256]; | |
832 GList *bud = NULL; | |
833 | |
834 | |
835 if (config != NULL) { | |
836 | |
837 /* skip "CONFIG:" (if it exists) */ | |
838 c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ? | |
839 strtok(config, "\n") : | |
840 strtok(config + 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n"); | |
841 do { | |
842 if (c == NULL) | |
843 break; | |
844 if (*c == 'g') { | |
845 char *utf8 = NULL; | |
846 utf8 = gaim_try_conv_to_utf8(c + 2); | |
847 if (utf8 == NULL) { | |
848 g_strlcpy(current, _("Invalid Groupname"), sizeof(current)); | |
849 } else { | |
850 g_strlcpy(current, utf8, sizeof(current)); | |
851 g_free(utf8); | |
852 } | |
853 if (!gaim_find_group(current)) { | |
854 struct group *g = gaim_group_new(current); | |
855 gaim_blist_add_group(g, NULL); | |
856 } | |
857 } else if (*c == 'b') { /*&& !gaim_find_buddy(user, c + 2)) {*/ | |
858 char nm[80], sw[388], *a, *utf8 = NULL; | |
859 | |
860 if ((a = strchr(c + 2, ':')) != NULL) { | |
861 *a++ = '\0'; /* nul the : */ | |
862 } | |
863 | |
864 g_strlcpy(nm, c + 2, sizeof(nm)); | |
865 if (a) { | |
866 utf8 = gaim_try_conv_to_utf8(a); | |
867 if (utf8 == NULL) { | |
868 gaim_debug(GAIM_DEBUG_ERROR, "toc blist", | |
869 "Failed to convert alias for " | |
870 "'%s' to UTF-8\n", nm); | |
871 } | |
872 } | |
873 if (utf8 == NULL) { | |
874 sw[0] = '\0'; | |
875 } else { | |
876 /* This can leave a partial sequence at the end, | |
877 * but who cares? */ | |
878 g_strlcpy(sw, utf8, sizeof(sw)); | |
879 g_free(utf8); | |
880 } | |
881 | |
882 if (!gaim_find_buddy(account, nm)) { | |
883 struct buddy *b = gaim_buddy_new(account, nm, sw); | |
884 struct group *g = gaim_find_group(current); | |
885 gaim_blist_add_buddy(b, g, NULL); | |
886 bud = g_list_append(bud, g_strdup(nm)); | |
887 } | |
888 } else if (*c == 'p') { | |
889 gaim_privacy_permit_add(account, c + 2); | |
890 } else if (*c == 'd') { | |
891 gaim_privacy_deny_add(account, c + 2); | |
892 } else if (!strncmp("toc", c, 3)) { | |
893 sscanf(c + strlen(c) - 1, "%d", &account->permdeny); | |
894 gaim_debug(GAIM_DEBUG_MISC, "toc blist", | |
895 "permdeny: %d\n", account->permdeny); | |
896 if (account->permdeny == 0) | |
897 account->permdeny = 1; | |
898 } else if (*c == 'm') { | |
899 sscanf(c + 2, "%d", &account->permdeny); | |
900 gaim_debug(GAIM_DEBUG_MISC, "toc blist", | |
901 "permdeny: %d\n", account->permdeny); | |
902 if (account->permdeny == 0) | |
903 account->permdeny = 1; | |
904 } | |
905 } while ((c = strtok(NULL, "\n"))); | |
906 | |
907 if(account->gc) { | |
908 if(bud) { | |
909 GList *node = bud; | |
910 serv_add_buddies(account->gc, bud); | |
911 while(node) { | |
912 g_free(node->data); | |
913 node = node->next; | |
914 } | |
915 } | |
916 serv_set_permit_deny(account->gc); | |
917 } | |
918 g_list_free(bud); | |
919 } | |
920 } | |
921 | |
922 #if 0 | |
923 /* translate an AIM 3 buddylist (*.lst) to a Gaim buddylist */ | |
924 static GString *translate_lst(FILE *src_fp) | |
925 { | |
926 char line[BUF_LEN], *line2; | |
927 char *name; | |
928 int i; | |
929 | |
930 GString *dest = g_string_new("m 1\n"); | |
931 | |
932 while (fgets(line, BUF_LEN, src_fp)) { | |
933 line2 = g_strchug(line); | |
934 if (strstr(line2, "group") == line2) { | |
935 name = strpbrk(line2, " \t\n\r\f") + 1; | |
936 dest = g_string_append(dest, "g "); | |
937 for (i = 0; i < strcspn(name, "\n\r"); i++) | |
938 if (name[i] != '\"') | |
939 dest = g_string_append_c(dest, name[i]); | |
940 dest = g_string_append_c(dest, '\n'); | |
941 } | |
942 if (strstr(line2, "buddy") == line2) { | |
943 name = strpbrk(line2, " \t\n\r\f") + 1; | |
944 dest = g_string_append(dest, "b "); | |
945 for (i = 0; i < strcspn(name, "\n\r"); i++) | |
946 if (name[i] != '\"') | |
947 dest = g_string_append_c(dest, name[i]); | |
948 dest = g_string_append_c(dest, '\n'); | |
949 } | |
950 } | |
951 | |
952 return dest; | |
953 } | |
954 | |
955 | |
956 /* translate an AIM 4 buddylist (*.blt) to Gaim format */ | |
957 static GString *translate_blt(FILE *src_fp) | |
958 { | |
959 int i; | |
960 char line[BUF_LEN]; | |
961 char *buddy; | |
962 | |
963 GString *dest = g_string_new("m 1\n"); | |
964 | |
965 while (strstr(fgets(line, BUF_LEN, src_fp), "Buddy") == NULL); | |
966 while (strstr(fgets(line, BUF_LEN, src_fp), "list") == NULL); | |
967 | |
968 while (1) { | |
969 fgets(line, BUF_LEN, src_fp); g_strchomp(line); | |
970 if (strchr(line, '}') != NULL) | |
971 break; | |
972 | |
973 if (strchr(line, '{') != NULL) { | |
974 /* Syntax starting with "<group> {" */ | |
975 | |
976 dest = g_string_append(dest, "g "); | |
977 buddy = g_strchug(strtok(line, "{")); | |
978 for (i = 0; i < strlen(buddy); i++) | |
979 if (buddy[i] != '\"') | |
980 dest = g_string_append_c(dest, buddy[i]); | |
981 dest = g_string_append_c(dest, '\n'); | |
982 while (strchr(fgets(line, BUF_LEN, src_fp), '}') == NULL) { | |
983 gboolean pounce = FALSE; | |
984 char *e; | |
985 g_strchomp(line); | |
986 buddy = g_strchug(line); | |
987 gaim_debug(GAIM_DEBUG_MISC, "AIM 4 blt import", | |
988 "buddy: \"%s\"\n", buddy); | |
989 dest = g_string_append(dest, "b "); | |
990 if (strchr(buddy, '{') != NULL) { | |
991 /* buddy pounce, etc */ | |
992 char *pos = strchr(buddy, '{') - 1; | |
993 *pos = 0; | |
994 pounce = TRUE; | |
995 } | |
996 if ((e = strchr(buddy, '\"')) != NULL) { | |
997 *e = '\0'; | |
998 buddy++; | |
999 } | |
1000 dest = g_string_append(dest, buddy); | |
1001 dest = g_string_append_c(dest, '\n'); | |
1002 if (pounce) | |
1003 do | |
1004 fgets(line, BUF_LEN, src_fp); | |
1005 while (!strchr(line, '}')); | |
1006 } | |
1007 } else { | |
1008 | |
1009 /* Syntax "group buddy buddy ..." */ | |
1010 buddy = g_strchug(strtok(line, " \n")); | |
1011 dest = g_string_append(dest, "g "); | |
1012 if (strchr(buddy, '\"') != NULL) { | |
1013 dest = g_string_append(dest, &buddy[1]); | |
1014 dest = g_string_append_c(dest, ' '); | |
1015 buddy = g_strchug(strtok(NULL, " \n")); | |
1016 while (strchr(buddy, '\"') == NULL) { | |
1017 dest = g_string_append(dest, buddy); | |
1018 dest = g_string_append_c(dest, ' '); | |
1019 buddy = g_strchug(strtok(NULL, " \n")); | |
1020 } | |
1021 buddy[strlen(buddy) - 1] = '\0'; | |
1022 dest = g_string_append(dest, buddy); | |
1023 } else { | |
1024 dest = g_string_append(dest, buddy); | |
1025 } | |
1026 dest = g_string_append_c(dest, '\n'); | |
1027 while ((buddy = g_strchug(strtok(NULL, " \n"))) != NULL) { | |
1028 dest = g_string_append(dest, "b "); | |
1029 if (strchr(buddy, '\"') != NULL) { | |
1030 dest = g_string_append(dest, &buddy[1]); | |
1031 dest = g_string_append_c(dest, ' '); | |
1032 buddy = g_strchug(strtok(NULL, " \n")); | |
1033 while (strchr(buddy, '\"') == NULL) { | |
1034 dest = g_string_append(dest, buddy); | |
1035 dest = g_string_append_c(dest, ' '); | |
1036 buddy = g_strchug(strtok(NULL, " \n")); | |
1037 } | |
1038 buddy[strlen(buddy) - 1] = '\0'; | |
1039 dest = g_string_append(dest, buddy); | |
1040 } else { | |
1041 dest = g_string_append(dest, buddy); | |
1042 } | |
1043 dest = g_string_append_c(dest, '\n'); | |
1044 } | |
1045 } | |
1046 } | |
1047 | |
1048 return dest; | |
1049 } | |
1050 | |
1051 static GString *translate_gnomeicu(FILE *src_fp) | |
1052 { | |
1053 char line[BUF_LEN]; | |
1054 GString *dest = g_string_new("m 1\ng Buddies\n"); | |
1055 | |
1056 while (strstr(fgets(line, BUF_LEN, src_fp), "NewContacts") == NULL); | |
1057 | |
1058 while (fgets(line, BUF_LEN, src_fp)) { | |
1059 char *eq; | |
1060 g_strchomp(line); | |
1061 if (line[0] == '\n' || line[0] == '[') | |
1062 break; | |
1063 eq = strchr(line, '='); | |
1064 if (!eq) | |
1065 break; | |
1066 *eq = ':'; | |
1067 eq = strchr(eq, ','); | |
1068 if (eq) | |
1069 *eq = '\0'; | |
1070 dest = g_string_append(dest, "b "); | |
1071 dest = g_string_append(dest, line); | |
1072 dest = g_string_append_c(dest, '\n'); | |
1073 } | |
1074 | |
1075 return dest; | |
1076 } | |
1077 #endif | |
1078 | |
1079 static gchar *get_screenname_filename(const char *name) | |
1080 { | |
1081 gchar **split; | |
1082 gchar *good; | |
1083 gchar *ret; | |
1084 | |
1085 split = g_strsplit(name, G_DIR_SEPARATOR_S, -1); | |
1086 good = g_strjoinv(NULL, split); | |
1087 g_strfreev(split); | |
1088 | |
1089 ret = g_utf8_strup(good, -1); | |
1090 | |
1091 g_free(good); | |
1092 | |
1093 return ret; | |
1094 } | |
1095 | |
1096 static gboolean gaim_blist_read(const char *filename); | |
1097 | |
1098 | |
1099 static void do_import(struct gaim_account *account, const char *filename) | |
1100 { | |
1101 GString *buf = NULL; | |
1102 char first[64]; | |
1103 char path[PATHSIZE]; | |
1104 int len; | |
1105 FILE *f; | |
1106 struct stat st; | |
1107 | |
1108 if (filename) { | |
1109 g_snprintf(path, sizeof(path), "%s", filename); | |
1110 } else { | |
1111 char *g_screenname = get_screenname_filename(account->username); | |
1112 char *file = gaim_user_dir(); | |
1113 int protocol = (account->protocol == GAIM_PROTO_OSCAR) ? (isalpha(account->username[0]) ? GAIM_PROTO_TOC : GAIM_PROTO_ICQ): account->protocol; | |
1114 | |
1115 if (file != (char *)NULL) { | |
1116 sprintf(path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, protocol); | |
1117 g_free(g_screenname); | |
1118 } else { | |
1119 g_free(g_screenname); | |
1120 return; | |
1121 } | |
1122 } | |
1123 | |
1124 if (stat(path, &st)) { | |
1125 gaim_debug(GAIM_DEBUG_ERROR, "blist import", "Unable to stat %s.\n", | |
1126 path); | |
1127 return; | |
1128 } | |
1129 | |
1130 if (!(f = fopen(path, "r"))) { | |
1131 gaim_debug(GAIM_DEBUG_ERROR, "blist import", "Unable to open %s.\n", | |
1132 path); | |
1133 return; | |
1134 } | |
1135 | |
1136 fgets(first, 64, f); | |
1137 | |
1138 if ((first[0] == '\n') || (first[0] == '\r' && first[1] == '\n')) | |
1139 fgets(first, 64, f); | |
1140 | |
1141 #if 0 | |
1142 if (!g_strncasecmp(first, "<xml", strlen("<xml"))) { | |
1143 /* new gaim XML buddy list */ | |
1144 gaim_blist_read(path); | |
1145 | |
1146 /* We really don't need to bother doing stuf like translating AIM 3 buddy lists anymore */ | |
1147 | |
1148 } else if (!g_strncasecmp(first, "Config {", strlen("Config {"))) { | |
1149 /* AIM 4 buddy list */ | |
1150 gaim_debug(GAIM_DEBUG_MISC, "blist import", "aim 4\n"); | |
1151 rewind(f); | |
1152 buf = translate_blt(f); | |
1153 } else if (strstr(first, "group") != NULL) { | |
1154 /* AIM 3 buddy list */ | |
1155 gaim_debug(GAIM_DEBUG_MISC, "blist import", "aim 3\n"); | |
1156 rewind(f); | |
1157 buf = translate_lst(f); | |
1158 } else if (!g_strncasecmp(first, "[User]", strlen("[User]"))) { | |
1159 /* GnomeICU (hopefully) */ | |
1160 gaim_debug(GAIM_DEBUG_MISC, "blist import", "gnomeicu\n"); | |
1161 rewind(f); | |
1162 buf = translate_gnomeicu(f); | |
1163 | |
1164 } else | |
1165 #endif | |
1166 if (first[0] == 'm') { | |
1167 /* Gaim buddy list - no translation */ | |
1168 char buf2[BUF_LONG * 2]; | |
1169 buf = g_string_new(""); | |
1170 rewind(f); | |
1171 while (1) { | |
1172 len = fread(buf2, 1, BUF_LONG * 2 - 1, f); | |
1173 if (len <= 0) | |
1174 break; | |
1175 buf2[len] = '\0'; | |
1176 buf = g_string_append(buf, buf2); | |
1177 if (len != BUF_LONG * 2 - 1) | |
1178 break; | |
1179 } | |
1180 } | |
1181 | |
1182 fclose(f); | |
1183 | |
1184 if (buf) { | |
1185 buf = g_string_prepend(buf, "toc_set_config {"); | |
1186 buf = g_string_append(buf, "}\n"); | |
1187 parse_toc_buddy_list(account, buf->str); | |
1188 g_string_free(buf, TRUE); | |
1189 } | |
1190 } | |
1191 | |
1192 gboolean gaim_group_on_account(struct group *g, struct gaim_account *account) { | |
1193 GaimBlistNode *bnode; | |
1194 for(bnode = g->node.child; bnode; bnode = bnode->next) { | |
1195 struct buddy *b = (struct buddy *)bnode; | |
1196 if(!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
1197 continue; | |
1198 if((!account && b->account->gc) || b->account == account) | |
1199 return TRUE; | |
1200 } | |
1201 return FALSE; | |
1202 } | |
1203 | |
1204 static gboolean blist_safe_to_write = FALSE; | |
1205 | |
1206 static char *blist_parser_group_name = NULL; | |
1207 static char *blist_parser_person_name = NULL; | |
1208 static char *blist_parser_account_name = NULL; | |
1209 static int blist_parser_account_protocol = 0; | |
5234 | 1210 static char *blist_parser_chat_alias = NULL; |
1211 static char *blist_parser_component_name = NULL; | |
1212 static char *blist_parser_component_value = NULL; | |
5228 | 1213 static char *blist_parser_buddy_name = NULL; |
1214 static char *blist_parser_buddy_alias = NULL; | |
1215 static char *blist_parser_setting_name = NULL; | |
1216 static char *blist_parser_setting_value = NULL; | |
1217 static GHashTable *blist_parser_buddy_settings = NULL; | |
1218 static GHashTable *blist_parser_group_settings = NULL; | |
5234 | 1219 static GHashTable *blist_parser_chat_components = NULL; |
5228 | 1220 static int blist_parser_privacy_mode = 0; |
1221 static GList *tag_stack = NULL; | |
1222 enum { | |
1223 BLIST_TAG_GAIM, | |
1224 BLIST_TAG_BLIST, | |
1225 BLIST_TAG_GROUP, | |
5234 | 1226 BLIST_TAG_CHAT, |
1227 BLIST_TAG_COMPONENT, | |
5228 | 1228 BLIST_TAG_PERSON, |
1229 BLIST_TAG_BUDDY, | |
1230 BLIST_TAG_NAME, | |
1231 BLIST_TAG_ALIAS, | |
1232 BLIST_TAG_SETTING, | |
1233 BLIST_TAG_PRIVACY, | |
1234 BLIST_TAG_ACCOUNT, | |
1235 BLIST_TAG_PERMIT, | |
1236 BLIST_TAG_BLOCK, | |
1237 BLIST_TAG_IGNORE | |
1238 }; | |
1239 static gboolean blist_parser_error_occurred = FALSE; | |
1240 | |
1241 static void blist_start_element_handler (GMarkupParseContext *context, | |
1242 const gchar *element_name, | |
1243 const gchar **attribute_names, | |
1244 const gchar **attribute_values, | |
1245 gpointer user_data, | |
1246 GError **error) { | |
1247 int i; | |
1248 | |
1249 if(!strcmp(element_name, "gaim")) { | |
1250 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_GAIM)); | |
1251 } else if(!strcmp(element_name, "blist")) { | |
1252 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_BLIST)); | |
1253 } else if(!strcmp(element_name, "group")) { | |
1254 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_GROUP)); | |
1255 for(i=0; attribute_names[i]; i++) { | |
1256 if(!strcmp(attribute_names[i], "name")) { | |
1257 g_free(blist_parser_group_name); | |
1258 blist_parser_group_name = g_strdup(attribute_values[i]); | |
1259 } | |
1260 } | |
1261 if(blist_parser_group_name) { | |
1262 struct group *g = gaim_group_new(blist_parser_group_name); | |
1263 gaim_blist_add_group(g,NULL); | |
1264 } | |
5234 | 1265 } else if(!strcmp(element_name, "chat")) { |
1266 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_CHAT)); | |
1267 for(i=0; attribute_names[i]; i++) { | |
1268 if(!strcmp(attribute_names[i], "account")) { | |
1269 g_free(blist_parser_account_name); | |
1270 blist_parser_account_name = g_strdup(attribute_values[i]); | |
1271 } else if(!strcmp(attribute_names[i], "protocol")) { | |
1272 blist_parser_account_protocol = atoi(attribute_values[i]); | |
1273 } | |
1274 } | |
5228 | 1275 } else if(!strcmp(element_name, "person")) { |
1276 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_PERSON)); | |
1277 for(i=0; attribute_names[i]; i++) { | |
1278 if(!strcmp(attribute_names[i], "name")) { | |
1279 g_free(blist_parser_person_name); | |
1280 blist_parser_person_name = g_strdup(attribute_values[i]); | |
1281 } | |
1282 } | |
1283 } else if(!strcmp(element_name, "buddy")) { | |
1284 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_BUDDY)); | |
1285 for(i=0; attribute_names[i]; i++) { | |
1286 if(!strcmp(attribute_names[i], "account")) { | |
1287 g_free(blist_parser_account_name); | |
1288 blist_parser_account_name = g_strdup(attribute_values[i]); | |
1289 } else if(!strcmp(attribute_names[i], "protocol")) { | |
1290 blist_parser_account_protocol = atoi(attribute_values[i]); | |
1291 } | |
1292 } | |
1293 } else if(!strcmp(element_name, "name")) { | |
1294 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_NAME)); | |
1295 } else if(!strcmp(element_name, "alias")) { | |
1296 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_ALIAS)); | |
1297 } else if(!strcmp(element_name, "setting")) { | |
1298 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_SETTING)); | |
1299 for(i=0; attribute_names[i]; i++) { | |
1300 if(!strcmp(attribute_names[i], "name")) { | |
1301 g_free(blist_parser_setting_name); | |
1302 blist_parser_setting_name = g_strdup(attribute_values[i]); | |
1303 } | |
1304 } | |
5234 | 1305 } else if(!strcmp(element_name, "component")) { |
1306 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_COMPONENT)); | |
1307 for(i=0; attribute_names[i]; i++) { | |
1308 if(!strcmp(attribute_names[i], "name")) { | |
1309 g_free(blist_parser_component_name); | |
1310 blist_parser_component_name = g_strdup(attribute_values[i]); | |
1311 } | |
1312 } | |
1313 | |
5228 | 1314 } else if(!strcmp(element_name, "privacy")) { |
1315 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_PRIVACY)); | |
1316 } else if(!strcmp(element_name, "account")) { | |
1317 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_ACCOUNT)); | |
1318 for(i=0; attribute_names[i]; i++) { | |
1319 if(!strcmp(attribute_names[i], "protocol")) | |
1320 blist_parser_account_protocol = atoi(attribute_values[i]); | |
1321 else if(!strcmp(attribute_names[i], "mode")) | |
1322 blist_parser_privacy_mode = atoi(attribute_values[i]); | |
1323 else if(!strcmp(attribute_names[i], "name")) { | |
1324 g_free(blist_parser_account_name); | |
1325 blist_parser_account_name = g_strdup(attribute_values[i]); | |
1326 } | |
1327 } | |
1328 } else if(!strcmp(element_name, "permit")) { | |
1329 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_PERMIT)); | |
1330 } else if(!strcmp(element_name, "block")) { | |
1331 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_BLOCK)); | |
1332 } else if(!strcmp(element_name, "ignore")) { | |
1333 tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_IGNORE)); | |
1334 } | |
1335 } | |
1336 | |
1337 static void blist_end_element_handler(GMarkupParseContext *context, | |
1338 const gchar *element_name, gpointer user_data, GError **error) { | |
1339 if(!strcmp(element_name, "gaim")) { | |
1340 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1341 } else if(!strcmp(element_name, "blist")) { | |
1342 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1343 } else if(!strcmp(element_name, "group")) { | |
1344 if(blist_parser_group_settings) { | |
1345 struct group *g = gaim_find_group(blist_parser_group_name); | |
1346 g_hash_table_destroy(g->settings); | |
1347 g->settings = blist_parser_group_settings; | |
1348 } | |
1349 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1350 blist_parser_group_settings = NULL; | |
5234 | 1351 } else if(!strcmp(element_name, "chat")) { |
1352 struct gaim_account *account = gaim_account_find(blist_parser_account_name, | |
1353 blist_parser_account_protocol); | |
5237 | 1354 if(account) { |
5234 | 1355 struct chat *chat = gaim_chat_new(account, blist_parser_chat_alias, blist_parser_chat_components); |
1356 struct group *g = gaim_find_group(blist_parser_group_name); | |
1357 gaim_blist_add_chat(chat,g,NULL); | |
1358 } | |
1359 g_free(blist_parser_chat_alias); | |
1360 blist_parser_chat_alias = NULL; | |
1361 g_free(blist_parser_account_name); | |
1362 blist_parser_account_name = NULL; | |
1363 blist_parser_chat_components = NULL; | |
1364 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
5228 | 1365 } else if(!strcmp(element_name, "person")) { |
1366 g_free(blist_parser_person_name); | |
1367 blist_parser_person_name = NULL; | |
1368 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1369 } else if(!strcmp(element_name, "buddy")) { | |
1370 struct gaim_account *account = gaim_account_find(blist_parser_account_name, | |
1371 blist_parser_account_protocol); | |
1372 if(account) { | |
1373 struct buddy *b = gaim_buddy_new(account, blist_parser_buddy_name, blist_parser_buddy_alias); | |
1374 struct group *g = gaim_find_group(blist_parser_group_name); | |
1375 gaim_blist_add_buddy(b,g,NULL); | |
1376 if(blist_parser_buddy_settings) { | |
1377 g_hash_table_destroy(b->settings); | |
1378 b->settings = blist_parser_buddy_settings; | |
1379 } | |
1380 } | |
1381 g_free(blist_parser_buddy_name); | |
1382 blist_parser_buddy_name = NULL; | |
1383 g_free(blist_parser_buddy_alias); | |
1384 blist_parser_buddy_alias = NULL; | |
1385 g_free(blist_parser_account_name); | |
1386 blist_parser_account_name = NULL; | |
1387 blist_parser_buddy_settings = NULL; | |
1388 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1389 } else if(!strcmp(element_name, "name")) { | |
1390 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1391 } else if(!strcmp(element_name, "alias")) { | |
1392 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
5234 | 1393 } else if(!strcmp(element_name, "component")) { |
1394 if(!blist_parser_chat_components) | |
1395 blist_parser_chat_components = g_hash_table_new_full(g_str_hash, | |
1396 g_str_equal, g_free, g_free); | |
1397 if(blist_parser_component_name && blist_parser_component_value) { | |
1398 g_hash_table_replace(blist_parser_chat_components, | |
1399 g_strdup(blist_parser_component_name), | |
1400 g_strdup(blist_parser_component_value)); | |
1401 } | |
1402 g_free(blist_parser_component_name); | |
1403 g_free(blist_parser_component_value); | |
1404 blist_parser_component_name = NULL; | |
1405 blist_parser_component_value = NULL; | |
1406 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
5228 | 1407 } else if(!strcmp(element_name, "setting")) { |
1408 if(GPOINTER_TO_INT(tag_stack->next->data) == BLIST_TAG_BUDDY) { | |
1409 if(!blist_parser_buddy_settings) | |
1410 blist_parser_buddy_settings = g_hash_table_new_full(g_str_hash, | |
1411 g_str_equal, g_free, g_free); | |
1412 if(blist_parser_setting_name && blist_parser_setting_value) { | |
1413 g_hash_table_replace(blist_parser_buddy_settings, | |
1414 g_strdup(blist_parser_setting_name), | |
1415 g_strdup(blist_parser_setting_value)); | |
1416 } | |
1417 } else if(GPOINTER_TO_INT(tag_stack->next->data) == BLIST_TAG_GROUP) { | |
1418 if(!blist_parser_group_settings) | |
1419 blist_parser_group_settings = g_hash_table_new_full(g_str_hash, | |
1420 g_str_equal, g_free, g_free); | |
1421 if(blist_parser_setting_name && blist_parser_setting_value) { | |
1422 g_hash_table_replace(blist_parser_group_settings, | |
1423 g_strdup(blist_parser_setting_name), | |
1424 g_strdup(blist_parser_setting_value)); | |
1425 } | |
1426 } | |
1427 g_free(blist_parser_setting_name); | |
1428 g_free(blist_parser_setting_value); | |
1429 blist_parser_setting_name = NULL; | |
1430 blist_parser_setting_value = NULL; | |
1431 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1432 } else if(!strcmp(element_name, "privacy")) { | |
1433 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1434 } else if(!strcmp(element_name, "account")) { | |
1435 struct gaim_account *account = gaim_account_find(blist_parser_account_name, | |
1436 blist_parser_account_protocol); | |
1437 if(account) { | |
1438 account->permdeny = blist_parser_privacy_mode; | |
1439 } | |
1440 g_free(blist_parser_account_name); | |
1441 blist_parser_account_name = NULL; | |
1442 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1443 } else if(!strcmp(element_name, "permit")) { | |
1444 struct gaim_account *account = gaim_account_find(blist_parser_account_name, | |
1445 blist_parser_account_protocol); | |
1446 if(account) { | |
1447 gaim_privacy_permit_add(account, blist_parser_buddy_name); | |
1448 } | |
1449 g_free(blist_parser_buddy_name); | |
1450 blist_parser_buddy_name = NULL; | |
1451 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1452 } else if(!strcmp(element_name, "block")) { | |
1453 struct gaim_account *account = gaim_account_find(blist_parser_account_name, | |
1454 blist_parser_account_protocol); | |
1455 if(account) { | |
1456 gaim_privacy_deny_add(account, blist_parser_buddy_name); | |
1457 } | |
1458 g_free(blist_parser_buddy_name); | |
1459 blist_parser_buddy_name = NULL; | |
1460 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1461 } else if(!strcmp(element_name, "ignore")) { | |
1462 /* we'll apparently do something with this later */ | |
1463 tag_stack = g_list_delete_link(tag_stack, tag_stack); | |
1464 } | |
1465 } | |
1466 | |
1467 static void blist_text_handler(GMarkupParseContext *context, const gchar *text, | |
1468 gsize text_len, gpointer user_data, GError **error) { | |
1469 switch(GPOINTER_TO_INT(tag_stack->data)) { | |
1470 case BLIST_TAG_NAME: | |
1471 blist_parser_buddy_name = g_strndup(text, text_len); | |
1472 break; | |
1473 case BLIST_TAG_ALIAS: | |
5234 | 1474 if(tag_stack->next && |
1475 GPOINTER_TO_INT(tag_stack->next->data) == BLIST_TAG_BUDDY) | |
1476 blist_parser_buddy_alias = g_strndup(text, text_len); | |
1477 else if(tag_stack->next && | |
1478 GPOINTER_TO_INT(tag_stack->next->data) == BLIST_TAG_CHAT) | |
1479 blist_parser_chat_alias = g_strndup(text, text_len); | |
5228 | 1480 break; |
1481 case BLIST_TAG_PERMIT: | |
1482 case BLIST_TAG_BLOCK: | |
1483 case BLIST_TAG_IGNORE: | |
1484 blist_parser_buddy_name = g_strndup(text, text_len); | |
1485 break; | |
5234 | 1486 case BLIST_TAG_COMPONENT: |
1487 blist_parser_component_value = g_strndup(text, text_len); | |
1488 break; | |
5228 | 1489 case BLIST_TAG_SETTING: |
1490 blist_parser_setting_value = g_strndup(text, text_len); | |
1491 break; | |
1492 default: | |
1493 break; | |
1494 } | |
1495 } | |
1496 | |
1497 static void blist_error_handler(GMarkupParseContext *context, GError *error, | |
1498 gpointer user_data) { | |
1499 blist_parser_error_occurred = TRUE; | |
1500 gaim_debug(GAIM_DEBUG_ERROR, "blist import", | |
1501 "Error parsing blist.xml: %s\n", error->message); | |
1502 } | |
1503 | |
1504 static GMarkupParser blist_parser = { | |
1505 blist_start_element_handler, | |
1506 blist_end_element_handler, | |
1507 blist_text_handler, | |
1508 NULL, | |
1509 blist_error_handler | |
1510 }; | |
1511 | |
1512 static gboolean gaim_blist_read(const char *filename) { | |
1513 gchar *contents = NULL; | |
1514 gsize length; | |
1515 GMarkupParseContext *context; | |
1516 GError *error = NULL; | |
1517 | |
1518 gaim_debug(GAIM_DEBUG_INFO, "blist import", | |
1519 "Reading %s\n", filename); | |
1520 if(!g_file_get_contents(filename, &contents, &length, &error)) { | |
1521 gaim_debug(GAIM_DEBUG_ERROR, "blist import", | |
1522 "Error reading blist: %s\n", error->message); | |
1523 g_error_free(error); | |
1524 return FALSE; | |
1525 } | |
1526 | |
1527 context = g_markup_parse_context_new(&blist_parser, 0, NULL, NULL); | |
1528 | |
1529 if(!g_markup_parse_context_parse(context, contents, length, NULL)) { | |
1530 g_markup_parse_context_free(context); | |
1531 g_free(contents); | |
1532 return FALSE; | |
1533 } | |
1534 | |
1535 if(!g_markup_parse_context_end_parse(context, NULL)) { | |
1536 gaim_debug(GAIM_DEBUG_ERROR, "blist import", | |
1537 "Error parsing %s\n", filename); | |
1538 g_markup_parse_context_free(context); | |
1539 g_free(contents); | |
1540 return FALSE; | |
1541 } | |
1542 | |
1543 g_markup_parse_context_free(context); | |
1544 g_free(contents); | |
1545 | |
1546 if(blist_parser_error_occurred) | |
1547 return FALSE; | |
1548 | |
1549 gaim_debug(GAIM_DEBUG_INFO, "blist import", "Finished reading %s\n", | |
1550 filename); | |
1551 | |
1552 return TRUE; | |
1553 } | |
1554 | |
1555 void gaim_blist_load() { | |
1556 GSList *accts; | |
1557 char *user_dir = gaim_user_dir(); | |
1558 char *filename; | |
1559 char *msg; | |
1560 | |
1561 blist_safe_to_write = TRUE; | |
1562 | |
1563 if(!user_dir) | |
1564 return; | |
1565 | |
1566 filename = g_build_filename(user_dir, "blist.xml", NULL); | |
1567 | |
1568 if(g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
1569 if(!gaim_blist_read(filename)) { | |
1570 msg = g_strdup_printf(_("An error was encountered parsing your " | |
1571 "buddy list. It has not been loaded.")); | |
1572 do_error_dialog(_("Buddy List Error"), msg, GAIM_ERROR); | |
1573 g_free(msg); | |
1574 } | |
1575 } else if(g_slist_length(gaim_accounts)) { | |
1576 /* rob wants to inform the user that their buddy lists are | |
1577 * being converted */ | |
1578 msg = g_strdup_printf(_("Gaim is converting your old buddy lists " | |
1579 "to a new format, which will now be located at %s"), | |
1580 filename); | |
1581 do_error_dialog(_("Converting Buddy List"), msg, GAIM_INFO); | |
1582 g_free(msg); | |
1583 | |
1584 /* now, let gtk actually display the dialog before we start anything */ | |
1585 while(gtk_events_pending()) | |
1586 gtk_main_iteration(); | |
1587 | |
1588 /* read in the old lists, then save to the new format */ | |
1589 for(accts = gaim_accounts; accts; accts = accts->next) { | |
1590 do_import(accts->data, NULL); | |
1591 } | |
1592 gaim_blist_save(); | |
1593 } | |
1594 | |
1595 g_free(filename); | |
1596 } | |
1597 | |
1598 static void blist_print_group_settings(gpointer key, gpointer data, | |
1599 gpointer user_data) { | |
1600 char *key_val; | |
1601 char *data_val; | |
1602 FILE *file = user_data; | |
1603 | |
1604 if(!key || !data) | |
1605 return; | |
1606 | |
1607 key_val = g_markup_escape_text(key, -1); | |
1608 data_val = g_markup_escape_text(data, -1); | |
1609 | |
1610 fprintf(file, "\t\t\t<setting name=\"%s\">%s</setting>\n", key_val, | |
1611 data_val); | |
1612 g_free(key_val); | |
1613 g_free(data_val); | |
1614 } | |
1615 | |
1616 static void blist_print_buddy_settings(gpointer key, gpointer data, | |
1617 gpointer user_data) { | |
1618 char *key_val; | |
1619 char *data_val; | |
1620 FILE *file = user_data; | |
1621 | |
1622 if(!key || !data) | |
1623 return; | |
1624 | |
1625 key_val = g_markup_escape_text(key, -1); | |
1626 data_val = g_markup_escape_text(data, -1); | |
1627 | |
1628 fprintf(file, "\t\t\t\t\t<setting name=\"%s\">%s</setting>\n", key_val, | |
1629 data_val); | |
1630 g_free(key_val); | |
1631 g_free(data_val); | |
1632 } | |
1633 | |
5234 | 1634 static void blist_print_chat_components(gpointer key, gpointer data, |
1635 gpointer user_data) { | |
1636 char *key_val; | |
1637 char *data_val; | |
1638 FILE *file = user_data; | |
1639 | |
1640 if(!key || !data) | |
1641 return; | |
1642 | |
1643 key_val = g_markup_escape_text(key, -1); | |
1644 data_val = g_markup_escape_text(data, -1); | |
1645 | |
1646 fprintf(file, "\t\t\t\t<component name=\"%s\">%s</component>\n", key_val, | |
1647 data_val); | |
1648 g_free(key_val); | |
1649 g_free(data_val); | |
1650 } | |
1651 | |
5228 | 1652 static void gaim_blist_write(FILE *file, struct gaim_account *exp_acct) { |
1653 GSList *accounts, *buds; | |
1654 GaimBlistNode *gnode,*bnode; | |
1655 struct group *group; | |
1656 struct buddy *bud; | |
1657 fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n"); | |
1658 fprintf(file, "<gaim version=\"1\">\n"); | |
1659 fprintf(file, "\t<blist>\n"); | |
1660 | |
1661 for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) { | |
1662 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
1663 continue; | |
1664 group = (struct group *)gnode; | |
1665 if(!exp_acct || gaim_group_on_account(group, exp_acct)) { | |
1666 char *group_name = g_markup_escape_text(group->name, -1); | |
1667 fprintf(file, "\t\t<group name=\"%s\">\n", group_name); | |
1668 g_hash_table_foreach(group->settings, blist_print_group_settings, file); | |
1669 for(bnode = gnode->child; bnode; bnode = bnode->next) { | |
5234 | 1670 if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) { |
1671 bud = (struct buddy *)bnode; | |
1672 if(!exp_acct || bud->account == exp_acct) { | |
1673 char *bud_name = g_markup_escape_text(bud->name, -1); | |
1674 char *bud_alias = NULL; | |
1675 char *acct_name = g_markup_escape_text(bud->account->username, -1); | |
1676 if(bud->alias) | |
1677 bud_alias= g_markup_escape_text(bud->alias, -1); | |
1678 fprintf(file, "\t\t\t<person name=\"%s\">\n", | |
1679 bud_alias ? bud_alias : bud_name); | |
1680 fprintf(file, "\t\t\t\t<buddy protocol=\"%d\" " | |
1681 "account=\"%s\">\n", bud->account->protocol, | |
1682 acct_name); | |
1683 fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name); | |
1684 if(bud_alias) { | |
1685 fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n", | |
1686 bud_alias); | |
1687 } | |
1688 g_hash_table_foreach(bud->settings, | |
1689 blist_print_buddy_settings, file); | |
1690 fprintf(file, "\t\t\t\t</buddy>\n"); | |
1691 fprintf(file, "\t\t\t</person>\n"); | |
1692 g_free(bud_name); | |
1693 g_free(bud_alias); | |
1694 g_free(acct_name); | |
5228 | 1695 } |
5234 | 1696 } else if(GAIM_BLIST_NODE_IS_CHAT(bnode)) { |
1697 struct chat *chat = (struct chat *)bnode; | |
1698 if(!exp_acct || chat->account == exp_acct) { | |
1699 char *acct_name = g_markup_escape_text(chat->account->username, -1); | |
1700 fprintf(file, "\t\t\t<chat protocol=\"%d\" account=\"%s\">\n", chat->account->protocol, acct_name); | |
5237 | 1701 if(chat->alias) { |
1702 char *chat_alias = g_markup_escape_text(chat->alias, -1); | |
1703 fprintf(file, "\t\t\t\t<alias>%s</alias>\n", chat_alias); | |
1704 g_free(chat_alias); | |
1705 } | |
5234 | 1706 g_hash_table_foreach(chat->components, |
1707 blist_print_chat_components, file); | |
1708 fprintf(file, "\t\t\t</chat>\n"); | |
5237 | 1709 g_free(acct_name); |
5234 | 1710 } |
5228 | 1711 } |
1712 } | |
1713 fprintf(file, "\t\t</group>\n"); | |
1714 g_free(group_name); | |
1715 } | |
1716 } | |
1717 | |
1718 fprintf(file, "\t</blist>\n"); | |
1719 fprintf(file, "\t<privacy>\n"); | |
1720 | |
1721 for(accounts = gaim_accounts; accounts; accounts = accounts->next) { | |
1722 struct gaim_account *account = accounts->data; | |
1723 char *acct_name = g_markup_escape_text(account->username, -1); | |
1724 if(!exp_acct || account == exp_acct) { | |
1725 fprintf(file, "\t\t<account protocol=\"%d\" name=\"%s\" " | |
1726 "mode=\"%d\">\n", account->protocol, acct_name, account->permdeny); | |
1727 for(buds = account->permit; buds; buds = buds->next) { | |
1728 char *bud_name = g_markup_escape_text(buds->data, -1); | |
1729 fprintf(file, "\t\t\t<permit>%s</permit>\n", bud_name); | |
1730 g_free(bud_name); | |
1731 } | |
1732 for(buds = account->deny; buds; buds = buds->next) { | |
1733 char *bud_name = g_markup_escape_text(buds->data, -1); | |
1734 fprintf(file, "\t\t\t<block>%s</block>\n", bud_name); | |
1735 g_free(bud_name); | |
1736 } | |
1737 fprintf(file, "\t\t</account>\n"); | |
1738 } | |
1739 g_free(acct_name); | |
1740 } | |
1741 | |
1742 fprintf(file, "\t</privacy>\n"); | |
1743 fprintf(file, "</gaim>\n"); | |
1744 } | |
1745 | |
1746 void gaim_blist_save() { | |
1747 FILE *file; | |
1748 char *user_dir = gaim_user_dir(); | |
1749 char *filename; | |
1750 char *filename_real; | |
1751 | |
1752 if(!user_dir) | |
1753 return; | |
1754 if(!blist_safe_to_write) { | |
1755 gaim_debug(GAIM_DEBUG_WARNING, "blist save", | |
1756 "AHH!! Tried to write the blist before we read it!\n"); | |
1757 return; | |
1758 } | |
1759 | |
1760 file = fopen(user_dir, "r"); | |
1761 if(!file) | |
1762 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); | |
1763 else | |
1764 fclose(file); | |
1765 | |
1766 filename = g_build_filename(user_dir, "blist.xml.save", NULL); | |
1767 | |
1768 if((file = fopen(filename, "w"))) { | |
1769 gaim_blist_write(file, NULL); | |
1770 fclose(file); | |
1771 chmod(filename, S_IRUSR | S_IWUSR); | |
1772 } else { | |
1773 gaim_debug(GAIM_DEBUG_ERROR, "blist save", "Unable to write %s\n", | |
1774 filename); | |
1775 } | |
1776 | |
1777 filename_real = g_build_filename(user_dir, "blist.xml", NULL); | |
1778 | |
1779 if(rename(filename, filename_real) < 0) | |
1780 gaim_debug(GAIM_DEBUG_ERROR, "blist save", | |
1781 "Error renaming %s to %s\n", filename, filename_real); | |
1782 | |
1783 | |
1784 g_free(filename); | |
1785 g_free(filename_real); | |
1786 } | |
1787 | |
1788 gboolean gaim_privacy_permit_add(struct gaim_account *account, const char *who) { | |
1789 GSList *d = account->permit; | |
1790 char *n = g_strdup(normalize(who)); | |
1791 while(d) { | |
1792 if(!gaim_utf8_strcasecmp(n, normalize(d->data))) | |
1793 break; | |
1794 d = d->next; | |
1795 } | |
1796 g_free(n); | |
1797 if(!d) { | |
1798 account->permit = g_slist_append(account->permit, g_strdup(who)); | |
1799 return TRUE; | |
1800 } | |
1801 | |
1802 return FALSE; | |
1803 } | |
1804 | |
1805 gboolean gaim_privacy_permit_remove(struct gaim_account *account, const char *who) { | |
1806 GSList *d = account->permit; | |
1807 char *n = g_strdup(normalize(who)); | |
1808 while(d) { | |
1809 if(!gaim_utf8_strcasecmp(n, normalize(d->data))) | |
1810 break; | |
1811 d = d->next; | |
1812 } | |
1813 g_free(n); | |
1814 if(d) { | |
1815 account->permit = g_slist_remove(account->permit, d->data); | |
1816 g_free(d->data); | |
1817 return TRUE; | |
1818 } | |
1819 return FALSE; | |
1820 } | |
1821 | |
1822 gboolean gaim_privacy_deny_add(struct gaim_account *account, const char *who) { | |
1823 GSList *d = account->deny; | |
1824 char *n = g_strdup(normalize(who)); | |
1825 while(d) { | |
1826 if(!gaim_utf8_strcasecmp(n, normalize(d->data))) | |
1827 break; | |
1828 d = d->next; | |
1829 } | |
1830 g_free(n); | |
1831 if(!d) { | |
1832 account->deny = g_slist_append(account->deny, g_strdup(who)); | |
1833 return TRUE; | |
1834 } | |
1835 | |
1836 return FALSE; | |
1837 } | |
1838 | |
1839 gboolean gaim_privacy_deny_remove(struct gaim_account *account, const char *who) { | |
1840 GSList *d = account->deny; | |
1841 char *n = g_strdup(normalize(who)); | |
1842 while(d) { | |
1843 if(!gaim_utf8_strcasecmp(n, normalize(d->data))) | |
1844 break; | |
1845 d = d->next; | |
1846 } | |
1847 g_free(n); | |
1848 if(d) { | |
1849 account->deny = g_slist_remove(account->deny, d->data); | |
1850 g_free(d->data); | |
1851 return TRUE; | |
1852 } | |
1853 return FALSE; | |
1854 } | |
1855 | |
1856 void gaim_group_set_setting(struct group *g, const char *key, | |
1857 const char *value) { | |
1858 if(!g) | |
1859 return; | |
1860 g_hash_table_replace(g->settings, g_strdup(key), g_strdup(value)); | |
1861 } | |
1862 | |
1863 char *gaim_group_get_setting(struct group *g, const char *key) { | |
1864 if(!g) | |
1865 return NULL; | |
1866 return g_strdup(g_hash_table_lookup(g->settings, key)); | |
1867 } | |
1868 | |
1869 void gaim_buddy_set_setting(struct buddy *b, const char *key, | |
1870 const char *value) { | |
1871 if(!b) | |
1872 return; | |
1873 g_hash_table_replace(b->settings, g_strdup(key), g_strdup(value)); | |
1874 } | |
1875 | |
1876 char *gaim_buddy_get_setting(struct buddy *b, const char *key) { | |
1877 if(!b) | |
1878 return NULL; | |
1879 return g_strdup(g_hash_table_lookup(b->settings, key)); | |
1880 } | |
1881 | |
1882 void gaim_set_blist_ui_ops(struct gaim_blist_ui_ops *ops) | |
1883 { | |
1884 blist_ui_ops = ops; | |
1885 } | |
1886 | |
1887 struct gaim_blist_ui_ops * | |
1888 gaim_get_blist_ui_ops(void) | |
1889 { | |
1890 return blist_ui_ops; | |
1891 } | |
1892 | |
1893 int gaim_blist_get_group_size(struct group *group, gboolean offline) { | |
1894 if(!group) | |
1895 return 0; | |
1896 | |
5277 | 1897 return offline ? group->totalsize : group->currentsize; |
5228 | 1898 } |
1899 | |
1900 int gaim_blist_get_group_online_count(struct group *group) { | |
1901 if(!group) | |
1902 return 0; | |
1903 | |
5277 | 1904 return group->online; |
5228 | 1905 } |
1906 | |
1907 |