Mercurial > pidgin.yaz
comparison src/blist.c @ 10428:04c663ccbcb1
[gaim-migrate @ 11680]
Shuffle some things around in blist.c and make some things more uniform.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 27 Dec 2004 04:43:49 +0000 |
parents | 16d63d8c26d8 |
children | e41f0668a648 |
comparison
equal
deleted
inserted
replaced
10427:16d63d8c26d8 | 10428:04c663ccbcb1 |
---|---|
49 }; | 49 }; |
50 | 50 |
51 static GaimBlistUiOps *blist_ui_ops = NULL; | 51 static GaimBlistUiOps *blist_ui_ops = NULL; |
52 | 52 |
53 static GaimBuddyList *gaimbuddylist = NULL; | 53 static GaimBuddyList *gaimbuddylist = NULL; |
54 static guint blist_save_timer = 0; | 54 static guint save_timer = 0; |
55 static gboolean blist_loaded = FALSE; | 55 static gboolean blist_loaded = FALSE; |
56 | 56 |
57 | 57 |
58 /***************************************************************************** | 58 /********************************************************************* |
59 * Private Utility functions * | 59 * Private utility functions * |
60 *****************************************************************************/ | 60 *********************************************************************/ |
61 | |
61 static GaimBlistNode *gaim_blist_get_last_sibling(GaimBlistNode *node) | 62 static GaimBlistNode *gaim_blist_get_last_sibling(GaimBlistNode *node) |
62 { | 63 { |
63 GaimBlistNode *n = node; | 64 GaimBlistNode *n = node; |
64 if (!n) | 65 if (!n) |
65 return NULL; | 66 return NULL; |
95 { | 96 { |
96 g_free(hb->name); | 97 g_free(hb->name); |
97 g_free(hb); | 98 g_free(hb); |
98 } | 99 } |
99 | 100 |
100 void gaim_contact_invalidate_priority_buddy(GaimContact *contact) | 101 |
101 { | 102 /********************************************************************* |
102 g_return_if_fail(contact != NULL); | 103 * Writting to disk * |
103 | 104 *********************************************************************/ |
104 contact->priority_valid = FALSE; | 105 |
105 } | 106 static void |
106 | 107 blist_print_setting(const char *key, |
107 static void gaim_contact_compute_priority_buddy(GaimContact *contact) | 108 struct gaim_blist_node_setting *setting, FILE *file, int indent) |
109 { | |
110 char *key_val, *data_val = NULL; | |
111 const char *type = NULL; | |
112 int i; | |
113 | |
114 if (!key) | |
115 return; | |
116 | |
117 switch(setting->type) { | |
118 case GAIM_BLIST_NODE_SETTING_BOOL: | |
119 type = "bool"; | |
120 data_val = g_strdup_printf("%d", setting->value.boolean); | |
121 break; | |
122 case GAIM_BLIST_NODE_SETTING_INT: | |
123 type = "int"; | |
124 data_val = g_strdup_printf("%d", setting->value.integer); | |
125 break; | |
126 case GAIM_BLIST_NODE_SETTING_STRING: | |
127 if (!setting->value.string) | |
128 return; | |
129 | |
130 type = "string"; | |
131 data_val = g_markup_escape_text(setting->value.string, -1); | |
132 break; | |
133 } | |
134 | |
135 /* this can't happen */ | |
136 if (!type || !data_val) | |
137 return; | |
138 | |
139 for (i=0; i<indent; i++) fprintf(file, "\t"); | |
140 | |
141 key_val = g_markup_escape_text(key, -1); | |
142 fprintf(file, "<setting name=\"%s\" type=\"%s\">%s</setting>\n", key_val, type, | |
143 data_val); | |
144 | |
145 g_free(key_val); | |
146 g_free(data_val); | |
147 } | |
148 | |
149 static void | |
150 blist_print_group_settings(gpointer key, gpointer data, | |
151 gpointer user_data) | |
152 { | |
153 blist_print_setting(key, data, user_data, 3); | |
154 } | |
155 | |
156 static void | |
157 blist_print_buddy_settings(gpointer key, gpointer data, | |
158 gpointer user_data) | |
159 { | |
160 blist_print_setting(key, data, user_data, 5); | |
161 } | |
162 | |
163 static void | |
164 blist_print_cnode_settings(gpointer key, gpointer data, | |
165 gpointer user_data) | |
166 { | |
167 blist_print_setting(key, data, user_data, 4); | |
168 } | |
169 | |
170 static void | |
171 blist_print_chat_components(gpointer key, gpointer data, | |
172 gpointer user_data) | |
173 { | |
174 char *key_val; | |
175 char *data_val; | |
176 FILE *file = user_data; | |
177 | |
178 if (!key || !data) | |
179 return; | |
180 | |
181 key_val = g_markup_escape_text(key, -1); | |
182 data_val = g_markup_escape_text(data, -1); | |
183 | |
184 fprintf(file, "\t\t\t\t<component name=\"%s\">%s</component>\n", key_val, | |
185 data_val); | |
186 g_free(key_val); | |
187 g_free(data_val); | |
188 } | |
189 | |
190 static void | |
191 print_buddy(FILE *file, GaimBuddy *buddy) | |
192 { | |
193 char *bud_name = g_markup_escape_text(buddy->name, -1); | |
194 char *bud_alias = NULL; | |
195 char *acct_name = g_markup_escape_text(buddy->account->username, -1); | |
196 if (buddy->alias) | |
197 bud_alias= g_markup_escape_text(buddy->alias, -1); | |
198 fprintf(file, "\t\t\t\t<buddy account=\"%s\" proto=\"%s\">\n", acct_name, | |
199 gaim_account_get_protocol_id(buddy->account)); | |
200 | |
201 fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name); | |
202 if (bud_alias) { | |
203 fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n", bud_alias); | |
204 } | |
205 g_hash_table_foreach(buddy->node.settings, blist_print_buddy_settings, file); | |
206 fprintf(file, "\t\t\t\t</buddy>\n"); | |
207 g_free(bud_name); | |
208 g_free(bud_alias); | |
209 g_free(acct_name); | |
210 } | |
211 | |
212 /* check for flagging and account exclusion on buddy */ | |
213 static gboolean | |
214 blist_buddy_should_save(GaimAccount *exp_acct, GaimBuddy *buddy) | |
215 { | |
216 if (! GAIM_BLIST_NODE_SHOULD_SAVE((GaimBlistNode *) buddy)) | |
217 return FALSE; | |
218 | |
219 if (exp_acct && buddy->account != exp_acct) | |
220 return FALSE; | |
221 | |
222 return TRUE; | |
223 } | |
224 | |
225 static void | |
226 blist_write_buddy(FILE *file, GaimAccount *exp_acct, GaimBuddy *buddy) | |
227 { | |
228 if (blist_buddy_should_save(exp_acct, buddy)) | |
229 print_buddy(file, buddy); | |
230 } | |
231 | |
232 /* check for flagging and account exclusion on contact and all members */ | |
233 static gboolean | |
234 blist_contact_should_save(GaimAccount *exp_acct, GaimContact *contact) | |
235 { | |
236 GaimBlistNode *bnode, *cnode = (GaimBlistNode *) contact; | |
237 | |
238 if (! GAIM_BLIST_NODE_SHOULD_SAVE(cnode)) | |
239 return FALSE; | |
240 | |
241 for (bnode = cnode->child; bnode; bnode = bnode->next) { | |
242 if (! GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
243 continue; | |
244 | |
245 if (blist_buddy_should_save(exp_acct, (GaimBuddy *) bnode)) | |
246 return TRUE; | |
247 } | |
248 | |
249 return FALSE; | |
250 } | |
251 | |
252 static void | |
253 blist_write_contact(FILE *file, GaimAccount *exp_acct, GaimContact *contact) | |
254 { | |
255 GaimBlistNode *bnode, *cnode = (GaimBlistNode *) contact; | |
256 | |
257 if (!blist_contact_should_save(exp_acct, contact)) | |
258 return; | |
259 | |
260 fprintf(file, "\t\t\t<contact"); | |
261 if (contact->alias) { | |
262 char *alias = g_markup_escape_text(contact->alias, -1); | |
263 fprintf(file, " alias=\"%s\"", alias); | |
264 g_free(alias); | |
265 } | |
266 fprintf(file, ">\n"); | |
267 | |
268 for (bnode = cnode->child; bnode; bnode = bnode->next) { | |
269 if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) { | |
270 blist_write_buddy(file, exp_acct, (GaimBuddy *) bnode); | |
271 } | |
272 } | |
273 | |
274 g_hash_table_foreach(cnode->settings, blist_print_cnode_settings, file); | |
275 fprintf(file, "\t\t\t</contact>\n"); | |
276 } | |
277 | |
278 static void | |
279 blist_write_chat(FILE *file, GaimAccount *exp_acct, GaimChat *chat) | |
280 { | |
281 char *acct_name; | |
282 | |
283 if (! GAIM_BLIST_NODE_SHOULD_SAVE((GaimBlistNode *) chat)) | |
284 return; | |
285 | |
286 if (exp_acct && chat->account != exp_acct) | |
287 return; | |
288 | |
289 acct_name = g_markup_escape_text(chat->account->username, -1); | |
290 fprintf(file, "\t\t\t<chat proto=\"%s\" account=\"%s\">\n", | |
291 gaim_account_get_protocol_id(chat->account), acct_name); | |
292 g_free(acct_name); | |
293 | |
294 if (chat->alias) { | |
295 char *chat_alias = g_markup_escape_text(chat->alias, -1); | |
296 fprintf(file, "\t\t\t\t<alias>%s</alias>\n", chat_alias); | |
297 g_free(chat_alias); | |
298 } | |
299 | |
300 g_hash_table_foreach(chat->components, blist_print_chat_components, file); | |
301 g_hash_table_foreach(chat->node.settings, blist_print_cnode_settings, file); | |
302 | |
303 fprintf(file, "\t\t\t</chat>\n"); | |
304 } | |
305 | |
306 static void | |
307 blist_write_group(FILE *file, GaimAccount *exp_acct, GaimGroup *group) | |
308 { | |
309 GaimBlistNode *cnode, *gnode = (GaimBlistNode *) group; | |
310 char *group_name; | |
311 | |
312 if (! GAIM_BLIST_NODE_SHOULD_SAVE(gnode)) | |
313 return; | |
314 | |
315 if (exp_acct && ! gaim_group_on_account(group, exp_acct)) | |
316 return; | |
317 | |
318 group_name = g_markup_escape_text(group->name, -1); | |
319 fprintf(file, "\t\t<group name=\"%s\">\n", group_name); | |
320 g_free(group_name); | |
321 | |
322 g_hash_table_foreach(group->node.settings, | |
323 blist_print_group_settings, file); | |
324 | |
325 for (cnode = gnode->child; cnode; cnode = cnode->next) { | |
326 if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) { | |
327 blist_write_contact(file, exp_acct, (GaimContact *) cnode); | |
328 } else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) { | |
329 blist_write_chat(file, exp_acct, (GaimChat *) cnode); | |
330 } | |
331 } | |
332 | |
333 fprintf(file, "\t\t</group>\n"); | |
334 } | |
335 | |
336 static void | |
337 blist_write_privacy_account(FILE *file, GaimAccount *exp_acct, GaimAccount *account) | |
338 { | |
339 char *acct_name; | |
340 GSList *buds; | |
341 | |
342 if(exp_acct && exp_acct != account) | |
343 return; | |
344 | |
345 acct_name = g_markup_escape_text(account->username, -1); | |
346 fprintf(file, "\t\t<account proto=\"%s\" name=\"%s\" mode=\"%d\">\n", | |
347 gaim_account_get_protocol_id(account), | |
348 acct_name, account->perm_deny); | |
349 g_free(acct_name); | |
350 | |
351 for (buds = account->permit; buds; buds = buds->next) { | |
352 char *bud_name = g_markup_escape_text(buds->data, -1); | |
353 fprintf(file, "\t\t\t<permit>%s</permit>\n", bud_name); | |
354 g_free(bud_name); | |
355 } | |
356 | |
357 for (buds = account->deny; buds; buds = buds->next) { | |
358 char *bud_name = g_markup_escape_text(buds->data, -1); | |
359 fprintf(file, "\t\t\t<block>%s</block>\n", bud_name); | |
360 g_free(bud_name); | |
361 } | |
362 | |
363 fprintf(file, "\t\t</account>\n"); | |
364 } | |
365 | |
366 static void | |
367 gaim_blist_write(FILE *file, GaimAccount *exp_acct) | |
368 { | |
369 GList *accounts; | |
370 GaimBlistNode *gnode; | |
371 | |
372 fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n\n"); | |
373 fprintf(file, "<gaim version='1.0'>\n"); | |
374 fprintf(file, "\t<blist>\n"); | |
375 | |
376 for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) { | |
377 if (GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
378 blist_write_group(file, exp_acct, (GaimGroup *) gnode); | |
379 } | |
380 | |
381 fprintf(file, "\t</blist>\n"); | |
382 fprintf(file, "\t<privacy>\n"); | |
383 | |
384 for (accounts = gaim_accounts_get_all(); accounts; accounts = accounts->next) { | |
385 blist_write_privacy_account(file, exp_acct, (GaimAccount *) accounts->data); | |
386 } | |
387 | |
388 fprintf(file, "\t</privacy>\n"); | |
389 fprintf(file, "</gaim>\n"); | |
390 } | |
391 | |
392 void | |
393 gaim_blist_sync() | |
394 { | |
395 FILE *file; | |
396 struct stat st; | |
397 const char *user_dir = gaim_user_dir(); | |
398 char *filename; | |
399 char *filename_real; | |
400 | |
401 g_return_if_fail(user_dir != NULL); | |
402 | |
403 if (!blist_loaded) { | |
404 gaim_debug_warning("blist save", | |
405 "AHH!! Tried to write the blist before we read it!\n"); | |
406 return; | |
407 } | |
408 | |
409 if (!g_file_test(user_dir, G_FILE_TEST_IS_DIR)) | |
410 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); | |
411 | |
412 filename = g_build_filename(user_dir, "blist.xml.save", NULL); | |
413 | |
414 if ((file = fopen(filename, "w"))) { | |
415 gaim_blist_write(file, NULL); | |
416 fclose(file); | |
417 chmod(filename, S_IRUSR | S_IWUSR); | |
418 } else { | |
419 gaim_debug_error("blist", "Unable to write %s\n", filename); | |
420 g_free(filename); | |
421 return; | |
422 } | |
423 | |
424 if (stat(filename, &st) || (st.st_size == 0)) { | |
425 gaim_debug_error("blist", "Failed to save blist\n"); | |
426 unlink(filename); | |
427 g_free(filename); | |
428 return; | |
429 } | |
430 | |
431 filename_real = g_build_filename(user_dir, "blist.xml", NULL); | |
432 | |
433 if (rename(filename, filename_real) < 0) | |
434 gaim_debug_error("blist", | |
435 "Error renaming %s to %s\n", filename, filename_real); | |
436 | |
437 g_free(filename); | |
438 g_free(filename_real); | |
439 } | |
440 | |
441 static gboolean | |
442 save_cb(gpointer data) | |
443 { | |
444 gaim_blist_sync(); | |
445 save_timer = 0; | |
446 return FALSE; | |
447 } | |
448 | |
449 static void | |
450 schedule_blist_save() | |
451 { | |
452 if (save_timer == 0) | |
453 save_timer = gaim_timeout_add(5000, save_cb, NULL); | |
454 } | |
455 | |
456 | |
457 /********************************************************************* | |
458 * Reading from disk * | |
459 *********************************************************************/ | |
460 | |
461 static void | |
462 parse_setting(GaimBlistNode *node, xmlnode *setting) | |
463 { | |
464 const char *name = xmlnode_get_attrib(setting, "name"); | |
465 const char *type = xmlnode_get_attrib(setting, "type"); | |
466 char *value = xmlnode_get_data(setting); | |
467 | |
468 if (!value) | |
469 return; | |
470 | |
471 if (!type || !strcmp(type, "string")) | |
472 gaim_blist_node_set_string(node, name, value); | |
473 else if (!strcmp(type, "bool")) | |
474 gaim_blist_node_set_bool(node, name, atoi(value)); | |
475 else if (!strcmp(type, "int")) | |
476 gaim_blist_node_set_int(node, name, atoi(value)); | |
477 | |
478 g_free(value); | |
479 } | |
480 | |
481 static void | |
482 parse_buddy(GaimGroup *group, GaimContact *contact, xmlnode *bnode) | |
483 { | |
484 GaimAccount *account; | |
485 GaimBuddy *buddy; | |
486 char *name = NULL, *alias = NULL; | |
487 const char *acct_name, *proto, *protocol; | |
488 xmlnode *x; | |
489 | |
490 acct_name = xmlnode_get_attrib(bnode, "account"); | |
491 protocol = xmlnode_get_attrib(bnode, "protocol"); | |
492 proto = xmlnode_get_attrib(bnode, "proto"); | |
493 | |
494 if (!acct_name || (!proto && !protocol)) | |
495 return; | |
496 | |
497 account = gaim_accounts_find(acct_name, proto ? proto : protocol); | |
498 | |
499 if (!account) | |
500 return; | |
501 | |
502 if ((x = xmlnode_get_child(bnode, "name"))) | |
503 name = xmlnode_get_data(x); | |
504 | |
505 if (!name) | |
506 return; | |
507 | |
508 if ((x = xmlnode_get_child(bnode, "alias"))) | |
509 alias = xmlnode_get_data(x); | |
510 | |
511 buddy = gaim_buddy_new(account, name, alias); | |
512 gaim_blist_add_buddy(buddy, contact, group, | |
513 gaim_blist_get_last_child((GaimBlistNode*)contact)); | |
514 | |
515 for (x = xmlnode_get_child(bnode, "setting"); x; x = xmlnode_get_next_twin(x)) { | |
516 parse_setting((GaimBlistNode*)buddy, x); | |
517 } | |
518 | |
519 g_free(name); | |
520 if (alias) | |
521 g_free(alias); | |
522 } | |
523 | |
524 static void | |
525 parse_contact(GaimGroup *group, xmlnode *cnode) | |
526 { | |
527 GaimContact *contact = gaim_contact_new(); | |
528 xmlnode *x; | |
529 const char *alias; | |
530 | |
531 gaim_blist_add_contact(contact, group, | |
532 gaim_blist_get_last_child((GaimBlistNode*)group)); | |
533 | |
534 if ((alias = xmlnode_get_attrib(cnode, "alias"))) { | |
535 gaim_contact_set_alias(contact, alias); | |
536 } | |
537 | |
538 for (x = cnode->child; x; x = x->next) { | |
539 if (x->type != XMLNODE_TYPE_TAG) | |
540 continue; | |
541 if (!strcmp(x->name, "buddy")) | |
542 parse_buddy(group, contact, x); | |
543 else if (!strcmp(x->name, "setting")) | |
544 parse_setting((GaimBlistNode*)contact, x); | |
545 } | |
546 | |
547 /* if the contact is empty, don't keep it around. it causes problems */ | |
548 if (!((GaimBlistNode*)contact)->child) | |
549 gaim_blist_remove_contact(contact); | |
550 } | |
551 | |
552 static void | |
553 parse_chat(GaimGroup *group, xmlnode *cnode) | |
554 { | |
555 GaimChat *chat; | |
556 GaimAccount *account; | |
557 const char *acct_name, *proto, *protocol; | |
558 xmlnode *x; | |
559 char *alias = NULL; | |
560 GHashTable *components; | |
561 | |
562 acct_name = xmlnode_get_attrib(cnode, "account"); | |
563 protocol = xmlnode_get_attrib(cnode, "protocol"); | |
564 proto = xmlnode_get_attrib(cnode, "proto"); | |
565 | |
566 if (!acct_name || (!proto && !protocol)) | |
567 return; | |
568 | |
569 account = gaim_accounts_find(acct_name, proto ? proto : protocol); | |
570 | |
571 if (!account) | |
572 return; | |
573 | |
574 if ((x = xmlnode_get_child(cnode, "alias"))) | |
575 alias = xmlnode_get_data(x); | |
576 | |
577 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
578 | |
579 for (x = xmlnode_get_child(cnode, "component"); x; x = xmlnode_get_next_twin(x)) { | |
580 const char *name; | |
581 char *value; | |
582 | |
583 name = xmlnode_get_attrib(x, "name"); | |
584 value = xmlnode_get_data(x); | |
585 g_hash_table_replace(components, g_strdup(name), value); | |
586 } | |
587 | |
588 chat = gaim_chat_new(account, alias, components); | |
589 gaim_blist_add_chat(chat, group, | |
590 gaim_blist_get_last_child((GaimBlistNode*)group)); | |
591 | |
592 for (x = xmlnode_get_child(cnode, "setting"); x; x = xmlnode_get_next_twin(x)) { | |
593 parse_setting((GaimBlistNode*)chat, x); | |
594 } | |
595 | |
596 if (alias) | |
597 g_free(alias); | |
598 } | |
599 | |
600 static void | |
601 parse_group(xmlnode *groupnode) | |
602 { | |
603 const char *name = xmlnode_get_attrib(groupnode, "name"); | |
604 GaimGroup *group; | |
605 xmlnode *cnode; | |
606 | |
607 if (!name) | |
608 name = _("Buddies"); | |
609 | |
610 group = gaim_group_new(name); | |
611 gaim_blist_add_group(group, | |
612 gaim_blist_get_last_sibling(gaimbuddylist->root)); | |
613 | |
614 for (cnode = groupnode->child; cnode; cnode = cnode->next) { | |
615 if (cnode->type != XMLNODE_TYPE_TAG) | |
616 continue; | |
617 if (!strcmp(cnode->name, "setting")) | |
618 parse_setting((GaimBlistNode*)group, cnode); | |
619 else if (!strcmp(cnode->name, "contact") || | |
620 !strcmp(cnode->name, "person")) | |
621 parse_contact(group, cnode); | |
622 else if (!strcmp(cnode->name, "chat")) | |
623 parse_chat(group, cnode); | |
624 } | |
625 } | |
626 | |
627 /* TODO: Make static and rename to load_blist */ | |
628 void | |
629 gaim_blist_load() | |
630 { | |
631 xmlnode *gaim, *blist, *privacy; | |
632 | |
633 blist_loaded = TRUE; | |
634 | |
635 gaim = gaim_util_read_xml_from_file("blist.xml", _("buddy list")); | |
636 | |
637 if (gaim == NULL) | |
638 return; | |
639 | |
640 blist = xmlnode_get_child(gaim, "blist"); | |
641 if (blist) { | |
642 xmlnode *groupnode; | |
643 for (groupnode = xmlnode_get_child(blist, "group"); groupnode != NULL; | |
644 groupnode = xmlnode_get_next_twin(groupnode)) { | |
645 parse_group(groupnode); | |
646 } | |
647 } | |
648 | |
649 privacy = xmlnode_get_child(gaim, "privacy"); | |
650 if (privacy) { | |
651 xmlnode *anode; | |
652 for (anode = privacy->child; anode; anode = anode->next) { | |
653 xmlnode *x; | |
654 GaimAccount *account; | |
655 const char *acct_name, *proto, *mode, *protocol; | |
656 | |
657 acct_name = xmlnode_get_attrib(anode, "name"); | |
658 protocol = xmlnode_get_attrib(anode, "protocol"); | |
659 proto = xmlnode_get_attrib(anode, "proto"); | |
660 mode = xmlnode_get_attrib(anode, "mode"); | |
661 | |
662 if (!acct_name || (!proto && !protocol) || !mode) | |
663 continue; | |
664 | |
665 account = gaim_accounts_find(acct_name, proto ? proto : protocol); | |
666 | |
667 if (!account) | |
668 continue; | |
669 | |
670 account->perm_deny = atoi(mode); | |
671 | |
672 for (x = anode->child; x; x = x->next) { | |
673 char *name; | |
674 if (x->type != XMLNODE_TYPE_TAG) | |
675 continue; | |
676 | |
677 if (!strcmp(x->name, "permit")) { | |
678 name = xmlnode_get_data(x); | |
679 gaim_privacy_permit_add(account, name, TRUE); | |
680 g_free(name); | |
681 } else if (!strcmp(x->name, "block")) { | |
682 name = xmlnode_get_data(x); | |
683 gaim_privacy_deny_add(account, name, TRUE); | |
684 g_free(name); | |
685 } | |
686 } | |
687 } | |
688 } | |
689 | |
690 xmlnode_free(gaim); | |
691 } | |
692 | |
693 | |
694 /********************************************************************* | |
695 * Stuff * | |
696 *********************************************************************/ | |
697 | |
698 static void | |
699 gaim_contact_compute_priority_buddy(GaimContact *contact) | |
108 { | 700 { |
109 GaimBlistNode *bnode; | 701 GaimBlistNode *bnode; |
110 GaimBuddy *new_priority = NULL; | 702 GaimBuddy *new_priority = NULL; |
111 | 703 |
112 g_return_if_fail(contact != NULL); | 704 g_return_if_fail(contact != NULL); |
142 } | 734 } |
143 } | 735 } |
144 | 736 |
145 contact->priority = new_priority; | 737 contact->priority = new_priority; |
146 contact->priority_valid = TRUE; | 738 contact->priority_valid = TRUE; |
147 } | |
148 | |
149 static gboolean blist_save_callback(gpointer data) | |
150 { | |
151 gaim_blist_sync(); | |
152 blist_save_timer = 0; | |
153 return FALSE; | |
154 } | |
155 | |
156 static void schedule_blist_save() | |
157 { | |
158 if (blist_save_timer != 0) | |
159 gaim_timeout_remove(blist_save_timer); | |
160 blist_save_timer = gaim_timeout_add(1000, blist_save_callback, NULL); | |
161 } | 739 } |
162 | 740 |
163 | 741 |
164 /***************************************************************************** | 742 /***************************************************************************** |
165 * Public API functions * | 743 * Public API functions * |
337 if (ops && ops->update) | 915 if (ops && ops->update) |
338 ops->update(gaimbuddylist, (GaimBlistNode *)buddy); | 916 ops->update(gaimbuddylist, (GaimBlistNode *)buddy); |
339 } | 917 } |
340 | 918 |
341 /* | 919 /* |
342 * XXX - Maybe remove the call to this from server.c and call it | 920 * TODO: Maybe remove the call to this from server.c and call it |
343 * from oscar.c and toc.c instead? | 921 * from oscar.c and toc.c instead? |
344 */ | 922 */ |
345 void gaim_blist_rename_buddy(GaimBuddy *buddy, const char *name) | 923 void gaim_blist_rename_buddy(GaimBuddy *buddy, const char *name) |
346 { | 924 { |
347 GaimBlistUiOps *ops = gaimbuddylist->ui_ops; | 925 GaimBlistUiOps *ops = gaimbuddylist->ui_ops; |
433 if (conv) | 1011 if (conv) |
434 gaim_conversation_autoset_title(conv); | 1012 gaim_conversation_autoset_title(conv); |
435 } | 1013 } |
436 | 1014 |
437 /* | 1015 /* |
438 * XXX - If merging, prompt the user if they want to merge. | 1016 * TODO: If merging, prompt the user if they want to merge. |
439 */ | 1017 */ |
440 void gaim_blist_rename_group(GaimGroup *source, const char *new_name) | 1018 void gaim_blist_rename_group(GaimGroup *source, const char *new_name) |
441 { | 1019 { |
442 GaimBlistUiOps *ops = gaimbuddylist->ui_ops; | 1020 GaimBlistUiOps *ops = gaimbuddylist->ui_ops; |
443 GaimGroup *dest; | 1021 GaimGroup *dest; |
458 | 1036 |
459 prev = gaim_blist_get_last_child((GaimBlistNode*)dest); | 1037 prev = gaim_blist_get_last_child((GaimBlistNode*)dest); |
460 child = ((GaimBlistNode*)source)->child; | 1038 child = ((GaimBlistNode*)source)->child; |
461 | 1039 |
462 /* | 1040 /* |
463 * XXX - This seems like a dumb way to do this... why not just | 1041 * TODO: This seems like a dumb way to do this... why not just |
464 * append all children from the old group to the end of the new | 1042 * append all children from the old group to the end of the new |
465 * one? PRPLs might be expecting to receive an add_buddy() for | 1043 * one? PRPLs might be expecting to receive an add_buddy() for |
466 * each moved buddy... | 1044 * each moved buddy... |
467 */ | 1045 */ |
468 while (child) | 1046 while (child) |
913 buddy = (GaimBuddy *)bnode; | 1491 buddy = (GaimBuddy *)bnode; |
914 if (buddy->account == account) | 1492 if (buddy->account == account) |
915 return TRUE; | 1493 return TRUE; |
916 } | 1494 } |
917 return FALSE; | 1495 return FALSE; |
1496 } | |
1497 | |
1498 void gaim_contact_invalidate_priority_buddy(GaimContact *contact) | |
1499 { | |
1500 g_return_if_fail(contact != NULL); | |
1501 | |
1502 contact->priority_valid = FALSE; | |
918 } | 1503 } |
919 | 1504 |
920 GaimGroup *gaim_group_new(const char *name) | 1505 GaimGroup *gaim_group_new(const char *name) |
921 { | 1506 { |
922 GaimBlistUiOps *ops = gaim_blist_get_ui_ops(); | 1507 GaimBlistUiOps *ops = gaim_blist_get_ui_ops(); |
1740 ((GaimGroup*)gnode)->currentsize--; | 2325 ((GaimGroup*)gnode)->currentsize--; |
1741 | 2326 |
1742 ((GaimBuddy*)bnode)->present = GAIM_BUDDY_OFFLINE; | 2327 ((GaimBuddy*)bnode)->present = GAIM_BUDDY_OFFLINE; |
1743 | 2328 |
1744 ((GaimBuddy*)bnode)->uc = 0; | 2329 ((GaimBuddy*)bnode)->uc = 0; |
1745 /* XXX ((GaimBuddy*)bnode)->idle = 0; */ | 2330 /* TODO: ((GaimBuddy*)bnode)->idle = 0; */ |
1746 | |
1747 | 2331 |
1748 if (ops && ops->remove) | 2332 if (ops && ops->remove) |
1749 ops->remove(gaimbuddylist, bnode); | 2333 ops->remove(gaimbuddylist, bnode); |
1750 } | 2334 } |
1751 } | 2335 } |
1780 } | 2364 } |
1781 } | 2365 } |
1782 return FALSE; | 2366 return FALSE; |
1783 } | 2367 } |
1784 | 2368 |
1785 static void parse_setting(GaimBlistNode *node, xmlnode *setting) | |
1786 { | |
1787 const char *name = xmlnode_get_attrib(setting, "name"); | |
1788 const char *type = xmlnode_get_attrib(setting, "type"); | |
1789 char *value = xmlnode_get_data(setting); | |
1790 | |
1791 if (!value) | |
1792 return; | |
1793 | |
1794 if (!type || !strcmp(type, "string")) | |
1795 gaim_blist_node_set_string(node, name, value); | |
1796 else if (!strcmp(type, "bool")) | |
1797 gaim_blist_node_set_bool(node, name, atoi(value)); | |
1798 else if (!strcmp(type, "int")) | |
1799 gaim_blist_node_set_int(node, name, atoi(value)); | |
1800 | |
1801 g_free(value); | |
1802 } | |
1803 | |
1804 static void parse_buddy(GaimGroup *group, GaimContact *contact, xmlnode *bnode) | |
1805 { | |
1806 GaimAccount *account; | |
1807 GaimBuddy *buddy; | |
1808 char *name = NULL, *alias = NULL; | |
1809 const char *acct_name, *proto, *protocol; | |
1810 xmlnode *x; | |
1811 | |
1812 acct_name = xmlnode_get_attrib(bnode, "account"); | |
1813 protocol = xmlnode_get_attrib(bnode, "protocol"); | |
1814 proto = xmlnode_get_attrib(bnode, "proto"); | |
1815 | |
1816 if (!acct_name || (!proto && !protocol)) | |
1817 return; | |
1818 | |
1819 account = gaim_accounts_find(acct_name, proto ? proto : protocol); | |
1820 | |
1821 if (!account) | |
1822 return; | |
1823 | |
1824 if ((x = xmlnode_get_child(bnode, "name"))) | |
1825 name = xmlnode_get_data(x); | |
1826 | |
1827 if (!name) | |
1828 return; | |
1829 | |
1830 if ((x = xmlnode_get_child(bnode, "alias"))) | |
1831 alias = xmlnode_get_data(x); | |
1832 | |
1833 buddy = gaim_buddy_new(account, name, alias); | |
1834 gaim_blist_add_buddy(buddy, contact, group, | |
1835 gaim_blist_get_last_child((GaimBlistNode*)contact)); | |
1836 | |
1837 for (x = xmlnode_get_child(bnode, "setting"); x; x = xmlnode_get_next_twin(x)) { | |
1838 parse_setting((GaimBlistNode*)buddy, x); | |
1839 } | |
1840 | |
1841 g_free(name); | |
1842 if (alias) | |
1843 g_free(alias); | |
1844 } | |
1845 | |
1846 static void parse_contact(GaimGroup *group, xmlnode *cnode) | |
1847 { | |
1848 GaimContact *contact = gaim_contact_new(); | |
1849 xmlnode *x; | |
1850 const char *alias; | |
1851 | |
1852 gaim_blist_add_contact(contact, group, | |
1853 gaim_blist_get_last_child((GaimBlistNode*)group)); | |
1854 | |
1855 if ((alias = xmlnode_get_attrib(cnode, "alias"))) { | |
1856 gaim_contact_set_alias(contact, alias); | |
1857 } | |
1858 | |
1859 for (x = cnode->child; x; x = x->next) { | |
1860 if (x->type != XMLNODE_TYPE_TAG) | |
1861 continue; | |
1862 if (!strcmp(x->name, "buddy")) | |
1863 parse_buddy(group, contact, x); | |
1864 else if (!strcmp(x->name, "setting")) | |
1865 parse_setting((GaimBlistNode*)contact, x); | |
1866 } | |
1867 | |
1868 /* if the contact is empty, don't keep it around. it causes problems */ | |
1869 if (!((GaimBlistNode*)contact)->child) | |
1870 gaim_blist_remove_contact(contact); | |
1871 } | |
1872 | |
1873 static void parse_chat(GaimGroup *group, xmlnode *cnode) | |
1874 { | |
1875 GaimChat *chat; | |
1876 GaimAccount *account; | |
1877 const char *acct_name, *proto, *protocol; | |
1878 xmlnode *x; | |
1879 char *alias = NULL; | |
1880 GHashTable *components; | |
1881 | |
1882 acct_name = xmlnode_get_attrib(cnode, "account"); | |
1883 protocol = xmlnode_get_attrib(cnode, "protocol"); | |
1884 proto = xmlnode_get_attrib(cnode, "proto"); | |
1885 | |
1886 if (!acct_name || (!proto && !protocol)) | |
1887 return; | |
1888 | |
1889 account = gaim_accounts_find(acct_name, proto ? proto : protocol); | |
1890 | |
1891 if (!account) | |
1892 return; | |
1893 | |
1894 if ((x = xmlnode_get_child(cnode, "alias"))) | |
1895 alias = xmlnode_get_data(x); | |
1896 | |
1897 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
1898 | |
1899 for (x = xmlnode_get_child(cnode, "component"); x; x = xmlnode_get_next_twin(x)) { | |
1900 const char *name; | |
1901 char *value; | |
1902 | |
1903 name = xmlnode_get_attrib(x, "name"); | |
1904 value = xmlnode_get_data(x); | |
1905 g_hash_table_replace(components, g_strdup(name), value); | |
1906 } | |
1907 | |
1908 chat = gaim_chat_new(account, alias, components); | |
1909 gaim_blist_add_chat(chat, group, | |
1910 gaim_blist_get_last_child((GaimBlistNode*)group)); | |
1911 | |
1912 for (x = xmlnode_get_child(cnode, "setting"); x; x = xmlnode_get_next_twin(x)) { | |
1913 parse_setting((GaimBlistNode*)chat, x); | |
1914 } | |
1915 | |
1916 if (alias) | |
1917 g_free(alias); | |
1918 } | |
1919 | |
1920 static void parse_group(xmlnode *groupnode) | |
1921 { | |
1922 const char *name = xmlnode_get_attrib(groupnode, "name"); | |
1923 GaimGroup *group; | |
1924 xmlnode *cnode; | |
1925 | |
1926 if (!name) | |
1927 name = _("Buddies"); | |
1928 | |
1929 group = gaim_group_new(name); | |
1930 gaim_blist_add_group(group, | |
1931 gaim_blist_get_last_sibling(gaimbuddylist->root)); | |
1932 | |
1933 for (cnode = groupnode->child; cnode; cnode = cnode->next) { | |
1934 if (cnode->type != XMLNODE_TYPE_TAG) | |
1935 continue; | |
1936 if (!strcmp(cnode->name, "setting")) | |
1937 parse_setting((GaimBlistNode*)group, cnode); | |
1938 else if (!strcmp(cnode->name, "contact") || | |
1939 !strcmp(cnode->name, "person")) | |
1940 parse_contact(group, cnode); | |
1941 else if (!strcmp(cnode->name, "chat")) | |
1942 parse_chat(group, cnode); | |
1943 } | |
1944 } | |
1945 | |
1946 void gaim_blist_load() | |
1947 { | |
1948 xmlnode *gaim, *blist, *privacy; | |
1949 | |
1950 blist_loaded = TRUE; | |
1951 | |
1952 gaim = gaim_util_read_xml_from_file("blist.xml", _("buddy list")); | |
1953 | |
1954 if (gaim == NULL) | |
1955 return; | |
1956 | |
1957 blist = xmlnode_get_child(gaim, "blist"); | |
1958 if (blist) { | |
1959 xmlnode *groupnode; | |
1960 for (groupnode = xmlnode_get_child(blist, "group"); groupnode != NULL; | |
1961 groupnode = xmlnode_get_next_twin(groupnode)) { | |
1962 parse_group(groupnode); | |
1963 } | |
1964 } | |
1965 | |
1966 privacy = xmlnode_get_child(gaim, "privacy"); | |
1967 if (privacy) { | |
1968 xmlnode *anode; | |
1969 for (anode = privacy->child; anode; anode = anode->next) { | |
1970 xmlnode *x; | |
1971 GaimAccount *account; | |
1972 const char *acct_name, *proto, *mode, *protocol; | |
1973 | |
1974 acct_name = xmlnode_get_attrib(anode, "name"); | |
1975 protocol = xmlnode_get_attrib(anode, "protocol"); | |
1976 proto = xmlnode_get_attrib(anode, "proto"); | |
1977 mode = xmlnode_get_attrib(anode, "mode"); | |
1978 | |
1979 if (!acct_name || (!proto && !protocol) || !mode) | |
1980 continue; | |
1981 | |
1982 account = gaim_accounts_find(acct_name, proto ? proto : protocol); | |
1983 | |
1984 if (!account) | |
1985 continue; | |
1986 | |
1987 account->perm_deny = atoi(mode); | |
1988 | |
1989 for (x = anode->child; x; x = x->next) { | |
1990 char *name; | |
1991 if (x->type != XMLNODE_TYPE_TAG) | |
1992 continue; | |
1993 | |
1994 if (!strcmp(x->name, "permit")) { | |
1995 name = xmlnode_get_data(x); | |
1996 gaim_privacy_permit_add(account, name, TRUE); | |
1997 g_free(name); | |
1998 } else if (!strcmp(x->name, "block")) { | |
1999 name = xmlnode_get_data(x); | |
2000 gaim_privacy_deny_add(account, name, TRUE); | |
2001 g_free(name); | |
2002 } | |
2003 } | |
2004 } | |
2005 } | |
2006 | |
2007 xmlnode_free(gaim); | |
2008 } | |
2009 | |
2010 void | 2369 void |
2011 gaim_blist_request_add_buddy(GaimAccount *account, const char *username, | 2370 gaim_blist_request_add_buddy(GaimAccount *account, const char *username, |
2012 const char *group, const char *alias) | 2371 const char *group, const char *alias) |
2013 { | 2372 { |
2014 GaimBlistUiOps *ui_ops; | 2373 GaimBlistUiOps *ui_ops; |
2039 ui_ops = gaim_blist_get_ui_ops(); | 2398 ui_ops = gaim_blist_get_ui_ops(); |
2040 | 2399 |
2041 if (ui_ops != NULL && ui_ops->request_add_group != NULL) | 2400 if (ui_ops != NULL && ui_ops->request_add_group != NULL) |
2042 ui_ops->request_add_group(); | 2401 ui_ops->request_add_group(); |
2043 } | 2402 } |
2044 | |
2045 static void blist_print_setting(const char *key, | |
2046 struct gaim_blist_node_setting *setting, FILE *file, int indent) | |
2047 { | |
2048 char *key_val, *data_val = NULL; | |
2049 const char *type = NULL; | |
2050 int i; | |
2051 | |
2052 if (!key) | |
2053 return; | |
2054 | |
2055 switch(setting->type) { | |
2056 case GAIM_BLIST_NODE_SETTING_BOOL: | |
2057 type = "bool"; | |
2058 data_val = g_strdup_printf("%d", setting->value.boolean); | |
2059 break; | |
2060 case GAIM_BLIST_NODE_SETTING_INT: | |
2061 type = "int"; | |
2062 data_val = g_strdup_printf("%d", setting->value.integer); | |
2063 break; | |
2064 case GAIM_BLIST_NODE_SETTING_STRING: | |
2065 if (!setting->value.string) | |
2066 return; | |
2067 | |
2068 type = "string"; | |
2069 data_val = g_markup_escape_text(setting->value.string, -1); | |
2070 break; | |
2071 } | |
2072 | |
2073 /* this can't happen */ | |
2074 if (!type || !data_val) | |
2075 return; | |
2076 | |
2077 for (i=0; i<indent; i++) fprintf(file, "\t"); | |
2078 | |
2079 key_val = g_markup_escape_text(key, -1); | |
2080 fprintf(file, "<setting name=\"%s\" type=\"%s\">%s</setting>\n", key_val, type, | |
2081 data_val); | |
2082 | |
2083 g_free(key_val); | |
2084 g_free(data_val); | |
2085 } | |
2086 | |
2087 static void blist_print_group_settings(gpointer key, gpointer data, | |
2088 gpointer user_data) | |
2089 { | |
2090 blist_print_setting(key, data, user_data, 3); | |
2091 } | |
2092 | |
2093 static void blist_print_buddy_settings(gpointer key, gpointer data, | |
2094 gpointer user_data) | |
2095 { | |
2096 blist_print_setting(key, data, user_data, 5); | |
2097 } | |
2098 | |
2099 static void blist_print_cnode_settings(gpointer key, gpointer data, | |
2100 gpointer user_data) | |
2101 { | |
2102 blist_print_setting(key, data, user_data, 4); | |
2103 } | |
2104 | |
2105 static void blist_print_chat_components(gpointer key, gpointer data, | |
2106 gpointer user_data) { | |
2107 char *key_val; | |
2108 char *data_val; | |
2109 FILE *file = user_data; | |
2110 | |
2111 if (!key || !data) | |
2112 return; | |
2113 | |
2114 key_val = g_markup_escape_text(key, -1); | |
2115 data_val = g_markup_escape_text(data, -1); | |
2116 | |
2117 fprintf(file, "\t\t\t\t<component name=\"%s\">%s</component>\n", key_val, | |
2118 data_val); | |
2119 g_free(key_val); | |
2120 g_free(data_val); | |
2121 } | |
2122 | |
2123 static void print_buddy(FILE *file, GaimBuddy *buddy) | |
2124 { | |
2125 char *bud_name = g_markup_escape_text(buddy->name, -1); | |
2126 char *bud_alias = NULL; | |
2127 char *acct_name = g_markup_escape_text(buddy->account->username, -1); | |
2128 if (buddy->alias) | |
2129 bud_alias= g_markup_escape_text(buddy->alias, -1); | |
2130 fprintf(file, "\t\t\t\t<buddy account=\"%s\" proto=\"%s\">\n", acct_name, | |
2131 gaim_account_get_protocol_id(buddy->account)); | |
2132 | |
2133 fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name); | |
2134 if (bud_alias) { | |
2135 fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n", bud_alias); | |
2136 } | |
2137 g_hash_table_foreach(buddy->node.settings, blist_print_buddy_settings, file); | |
2138 fprintf(file, "\t\t\t\t</buddy>\n"); | |
2139 g_free(bud_name); | |
2140 g_free(bud_alias); | |
2141 g_free(acct_name); | |
2142 } | |
2143 | |
2144 | |
2145 /* check for flagging and account exclusion on buddy */ | |
2146 static gboolean blist_buddy_should_save(GaimAccount *exp_acct, GaimBuddy *buddy) | |
2147 { | |
2148 if (! GAIM_BLIST_NODE_SHOULD_SAVE((GaimBlistNode *) buddy)) | |
2149 return FALSE; | |
2150 | |
2151 if (exp_acct && buddy->account != exp_acct) | |
2152 return FALSE; | |
2153 | |
2154 return TRUE; | |
2155 } | |
2156 | |
2157 | |
2158 static void blist_write_buddy(FILE *file, GaimAccount *exp_acct, GaimBuddy *buddy) | |
2159 { | |
2160 if (blist_buddy_should_save(exp_acct, buddy)) | |
2161 print_buddy(file, buddy); | |
2162 } | |
2163 | |
2164 | |
2165 /* check for flagging and account exclusion on contact and all members */ | |
2166 static gboolean blist_contact_should_save(GaimAccount *exp_acct, GaimContact *contact) | |
2167 { | |
2168 GaimBlistNode *bnode, *cnode = (GaimBlistNode *) contact; | |
2169 | |
2170 if (! GAIM_BLIST_NODE_SHOULD_SAVE(cnode)) | |
2171 return FALSE; | |
2172 | |
2173 for (bnode = cnode->child; bnode; bnode = bnode->next) { | |
2174 if (! GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
2175 continue; | |
2176 | |
2177 if (blist_buddy_should_save(exp_acct, (GaimBuddy *) bnode)) | |
2178 return TRUE; | |
2179 } | |
2180 | |
2181 return FALSE; | |
2182 } | |
2183 | |
2184 | |
2185 static void blist_write_contact(FILE *file, GaimAccount *exp_acct, GaimContact *contact) | |
2186 { | |
2187 GaimBlistNode *bnode, *cnode = (GaimBlistNode *) contact; | |
2188 | |
2189 if (!blist_contact_should_save(exp_acct, contact)) | |
2190 return; | |
2191 | |
2192 fprintf(file, "\t\t\t<contact"); | |
2193 if (contact->alias) { | |
2194 char *alias = g_markup_escape_text(contact->alias, -1); | |
2195 fprintf(file, " alias=\"%s\"", alias); | |
2196 g_free(alias); | |
2197 } | |
2198 fprintf(file, ">\n"); | |
2199 | |
2200 for (bnode = cnode->child; bnode; bnode = bnode->next) { | |
2201 if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) { | |
2202 blist_write_buddy(file, exp_acct, (GaimBuddy *) bnode); | |
2203 } | |
2204 } | |
2205 | |
2206 g_hash_table_foreach(cnode->settings, blist_print_cnode_settings, file); | |
2207 fprintf(file, "\t\t\t</contact>\n"); | |
2208 } | |
2209 | |
2210 | |
2211 static void blist_write_chat(FILE *file, GaimAccount *exp_acct, GaimChat *chat) | |
2212 { | |
2213 char *acct_name; | |
2214 | |
2215 if (! GAIM_BLIST_NODE_SHOULD_SAVE((GaimBlistNode *) chat)) | |
2216 return; | |
2217 | |
2218 if (exp_acct && chat->account != exp_acct) | |
2219 return; | |
2220 | |
2221 acct_name = g_markup_escape_text(chat->account->username, -1); | |
2222 fprintf(file, "\t\t\t<chat proto=\"%s\" account=\"%s\">\n", | |
2223 gaim_account_get_protocol_id(chat->account), acct_name); | |
2224 g_free(acct_name); | |
2225 | |
2226 if (chat->alias) { | |
2227 char *chat_alias = g_markup_escape_text(chat->alias, -1); | |
2228 fprintf(file, "\t\t\t\t<alias>%s</alias>\n", chat_alias); | |
2229 g_free(chat_alias); | |
2230 } | |
2231 | |
2232 g_hash_table_foreach(chat->components, blist_print_chat_components, file); | |
2233 g_hash_table_foreach(chat->node.settings, blist_print_cnode_settings, file); | |
2234 | |
2235 fprintf(file, "\t\t\t</chat>\n"); | |
2236 } | |
2237 | |
2238 | |
2239 static void blist_write_group(FILE *file, GaimAccount *exp_acct, GaimGroup *group) | |
2240 { | |
2241 GaimBlistNode *cnode, *gnode = (GaimBlistNode *) group; | |
2242 char *group_name; | |
2243 | |
2244 if (! GAIM_BLIST_NODE_SHOULD_SAVE(gnode)) | |
2245 return; | |
2246 | |
2247 if (exp_acct && ! gaim_group_on_account(group, exp_acct)) | |
2248 return; | |
2249 | |
2250 group_name = g_markup_escape_text(group->name, -1); | |
2251 fprintf(file, "\t\t<group name=\"%s\">\n", group_name); | |
2252 g_free(group_name); | |
2253 | |
2254 g_hash_table_foreach(group->node.settings, | |
2255 blist_print_group_settings, file); | |
2256 | |
2257 for (cnode = gnode->child; cnode; cnode = cnode->next) { | |
2258 if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) { | |
2259 blist_write_contact(file, exp_acct, (GaimContact *) cnode); | |
2260 } else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) { | |
2261 blist_write_chat(file, exp_acct, (GaimChat *) cnode); | |
2262 } | |
2263 } | |
2264 | |
2265 fprintf(file, "\t\t</group>\n"); | |
2266 } | |
2267 | |
2268 | |
2269 static void blist_write_privacy_account(FILE *file, GaimAccount *exp_acct, GaimAccount *account) | |
2270 { | |
2271 char *acct_name; | |
2272 GSList *buds; | |
2273 | |
2274 if(exp_acct && exp_acct != account) | |
2275 return; | |
2276 | |
2277 acct_name = g_markup_escape_text(account->username, -1); | |
2278 fprintf(file, "\t\t<account proto=\"%s\" name=\"%s\" mode=\"%d\">\n", | |
2279 gaim_account_get_protocol_id(account), | |
2280 acct_name, account->perm_deny); | |
2281 g_free(acct_name); | |
2282 | |
2283 for (buds = account->permit; buds; buds = buds->next) { | |
2284 char *bud_name = g_markup_escape_text(buds->data, -1); | |
2285 fprintf(file, "\t\t\t<permit>%s</permit>\n", bud_name); | |
2286 g_free(bud_name); | |
2287 } | |
2288 | |
2289 for (buds = account->deny; buds; buds = buds->next) { | |
2290 char *bud_name = g_markup_escape_text(buds->data, -1); | |
2291 fprintf(file, "\t\t\t<block>%s</block>\n", bud_name); | |
2292 g_free(bud_name); | |
2293 } | |
2294 | |
2295 fprintf(file, "\t\t</account>\n"); | |
2296 } | |
2297 | |
2298 | |
2299 static void gaim_blist_write(FILE *file, GaimAccount *exp_acct) | |
2300 { | |
2301 GList *accounts; | |
2302 GaimBlistNode *gnode; | |
2303 | |
2304 fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n\n"); | |
2305 fprintf(file, "<gaim version='1.0'>\n"); | |
2306 fprintf(file, "\t<blist>\n"); | |
2307 | |
2308 for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) { | |
2309 if (GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
2310 blist_write_group(file, exp_acct, (GaimGroup *) gnode); | |
2311 } | |
2312 | |
2313 fprintf(file, "\t</blist>\n"); | |
2314 fprintf(file, "\t<privacy>\n"); | |
2315 | |
2316 for (accounts = gaim_accounts_get_all(); accounts; accounts = accounts->next) { | |
2317 blist_write_privacy_account(file, exp_acct, (GaimAccount *) accounts->data); | |
2318 } | |
2319 | |
2320 fprintf(file, "\t</privacy>\n"); | |
2321 fprintf(file, "</gaim>\n"); | |
2322 } | |
2323 | |
2324 | |
2325 void gaim_blist_sync() | |
2326 { | |
2327 FILE *file; | |
2328 struct stat st; | |
2329 const char *user_dir = gaim_user_dir(); | |
2330 char *filename; | |
2331 char *filename_real; | |
2332 | |
2333 g_return_if_fail(user_dir != NULL); | |
2334 | |
2335 if (!blist_loaded) { | |
2336 gaim_debug_warning("blist save", | |
2337 "AHH!! Tried to write the blist before we read it!\n"); | |
2338 return; | |
2339 } | |
2340 | |
2341 if (!g_file_test(user_dir, G_FILE_TEST_IS_DIR)) | |
2342 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); | |
2343 | |
2344 filename = g_build_filename(user_dir, "blist.xml.save", NULL); | |
2345 | |
2346 if ((file = fopen(filename, "w"))) { | |
2347 gaim_blist_write(file, NULL); | |
2348 fclose(file); | |
2349 chmod(filename, S_IRUSR | S_IWUSR); | |
2350 } else { | |
2351 gaim_debug_error("blist", "Unable to write %s\n", filename); | |
2352 g_free(filename); | |
2353 return; | |
2354 } | |
2355 | |
2356 if (stat(filename, &st) || (st.st_size == 0)) { | |
2357 gaim_debug_error("blist", "Failed to save blist\n"); | |
2358 unlink(filename); | |
2359 g_free(filename); | |
2360 return; | |
2361 } | |
2362 | |
2363 filename_real = g_build_filename(user_dir, "blist.xml", NULL); | |
2364 | |
2365 if (rename(filename, filename_real) < 0) | |
2366 gaim_debug_error("blist", | |
2367 "Error renaming %s to %s\n", filename, filename_real); | |
2368 | |
2369 g_free(filename); | |
2370 g_free(filename_real); | |
2371 } | |
2372 | |
2373 | 2403 |
2374 static void gaim_blist_node_setting_free(struct gaim_blist_node_setting *setting) | 2404 static void gaim_blist_node_setting_free(struct gaim_blist_node_setting *setting) |
2375 { | 2405 { |
2376 switch(setting->type) { | 2406 switch(setting->type) { |
2377 case GAIM_BLIST_NODE_SETTING_BOOL: | 2407 case GAIM_BLIST_NODE_SETTING_BOOL: |
2402 g_hash_table_remove(node->settings, key); | 2432 g_hash_table_remove(node->settings, key); |
2403 | 2433 |
2404 schedule_blist_save(); | 2434 schedule_blist_save(); |
2405 } | 2435 } |
2406 | 2436 |
2407 | |
2408 void gaim_blist_node_set_bool(GaimBlistNode* node, const char *key, gboolean value) | 2437 void gaim_blist_node_set_bool(GaimBlistNode* node, const char *key, gboolean value) |
2409 { | 2438 { |
2410 struct gaim_blist_node_setting *setting; | 2439 struct gaim_blist_node_setting *setting; |
2411 | 2440 |
2412 g_return_if_fail(node != NULL); | 2441 g_return_if_fail(node != NULL); |
2520 gaim_signal_emit(gaim_blist_get_handle(), | 2549 gaim_signal_emit(gaim_blist_get_handle(), |
2521 "blist-node-extended-menu", | 2550 "blist-node-extended-menu", |
2522 n, &menu); | 2551 n, &menu); |
2523 return menu; | 2552 return menu; |
2524 } | 2553 } |
2525 | |
2526 | 2554 |
2527 GaimBlistNodeAction * | 2555 GaimBlistNodeAction * |
2528 gaim_blist_node_action_new(char *label, | 2556 gaim_blist_node_action_new(char *label, |
2529 void (*callback)(GaimBlistNode *, gpointer), | 2557 void (*callback)(GaimBlistNode *, gpointer), |
2530 gpointer data) | 2558 gpointer data) |
2533 act->label = label; | 2561 act->label = label; |
2534 act->callback = callback; | 2562 act->callback = callback; |
2535 act->data = data; | 2563 act->data = data; |
2536 return act; | 2564 return act; |
2537 } | 2565 } |
2538 | |
2539 | 2566 |
2540 int gaim_blist_get_group_size(GaimGroup *group, gboolean offline) | 2567 int gaim_blist_get_group_size(GaimGroup *group, gboolean offline) |
2541 { | 2568 { |
2542 if (!group) | 2569 if (!group) |
2543 return 0; | 2570 return 0; |
2622 } | 2649 } |
2623 | 2650 |
2624 void | 2651 void |
2625 gaim_blist_uninit(void) | 2652 gaim_blist_uninit(void) |
2626 { | 2653 { |
2627 if (blist_save_timer != 0) { | 2654 if (save_timer != 0) |
2628 gaim_timeout_remove(blist_save_timer); | 2655 { |
2629 blist_save_timer = 0; | 2656 gaim_timeout_remove(save_timer); |
2657 save_timer = 0; | |
2630 gaim_blist_sync(); | 2658 gaim_blist_sync(); |
2631 } | 2659 } |
2632 | 2660 |
2633 gaim_signals_unregister_by_instance(gaim_blist_get_handle()); | 2661 gaim_signals_unregister_by_instance(gaim_blist_get_handle()); |
2634 } | 2662 } |