comparison src/blist.c @ 10429:e41f0668a648

[gaim-migrate @ 11681] blist.xml is now written using the util function and xmlnodes. Let no one ever ever complain about losing their blist because their hard drive was full. prefs and pounces are the only two xml files not use the util functions and xmlnodes. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 27 Dec 2004 06:24:22 +0000
parents 04c663ccbcb1
children f5508fbf6764
comparison
equal deleted inserted replaced
10428:04c663ccbcb1 10429:e41f0668a648
33 #include "util.h" 33 #include "util.h"
34 #include "xmlnode.h" 34 #include "xmlnode.h"
35 35
36 #define PATHSIZE 1024 36 #define PATHSIZE 1024
37 37
38 /* TODO: Should use GaimValue instead of this. */
38 struct gaim_blist_node_setting { 39 struct gaim_blist_node_setting {
39 enum { 40 enum {
40 GAIM_BLIST_NODE_SETTING_BOOL, 41 GAIM_BLIST_NODE_SETTING_BOOL,
41 GAIM_BLIST_NODE_SETTING_INT, 42 GAIM_BLIST_NODE_SETTING_INT,
42 GAIM_BLIST_NODE_SETTING_STRING 43 GAIM_BLIST_NODE_SETTING_STRING
98 g_free(hb); 99 g_free(hb);
99 } 100 }
100 101
101 102
102 /********************************************************************* 103 /*********************************************************************
103 * Writting to disk * 104 * Writing to disk *
104 *********************************************************************/ 105 *********************************************************************/
105 106
106 static void 107 static void
107 blist_print_setting(const char *key, 108 setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
108 struct gaim_blist_node_setting *setting, FILE *file, int indent) 109 {
109 { 110 const char *name;
110 char *key_val, *data_val = NULL; 111 struct gaim_blist_node_setting *setting;
111 const char *type = NULL; 112 xmlnode *node, *child;
112 int i; 113 char buf[20];
113 114
114 if (!key) 115 name = (const char *)key;
115 return; 116 setting = (struct gaim_blist_node_setting *)value;
116 117 node = (xmlnode *)user_data;
117 switch(setting->type) { 118
118 case GAIM_BLIST_NODE_SETTING_BOOL: 119 child = xmlnode_new_child(node, "setting");
119 type = "bool"; 120 xmlnode_set_attrib(child, "name", name);
120 data_val = g_strdup_printf("%d", setting->value.boolean); 121
121 break; 122 if (setting->type == GAIM_BLIST_NODE_SETTING_INT) {
122 case GAIM_BLIST_NODE_SETTING_INT: 123 xmlnode_set_attrib(child, "type", "int");
123 type = "int"; 124 snprintf(buf, sizeof(buf), "%d", setting->value.integer);
124 data_val = g_strdup_printf("%d", setting->value.integer); 125 xmlnode_insert_data(child, buf, -1);
125 break; 126 }
126 case GAIM_BLIST_NODE_SETTING_STRING: 127 else if (setting->type == GAIM_BLIST_NODE_SETTING_STRING) {
127 if (!setting->value.string) 128 xmlnode_set_attrib(child, "type", "string");
128 return; 129 xmlnode_insert_data(child, setting->value.string, -1);
129 130 }
130 type = "string"; 131 else if (setting->type == GAIM_BLIST_NODE_SETTING_BOOL) {
131 data_val = g_markup_escape_text(setting->value.string, -1); 132 xmlnode_set_attrib(child, "type", "bool");
132 break; 133 snprintf(buf, sizeof(buf), "%d", setting->value.boolean);
133 } 134 xmlnode_insert_data(child, buf, -1);
134 135 }
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 } 136 }
148 137
149 static void 138 static void
150 blist_print_group_settings(gpointer key, gpointer data, 139 chat_component_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
151 gpointer user_data) 140 {
152 { 141 const char *name;
153 blist_print_setting(key, data, user_data, 3); 142 const char *data;
154 } 143 xmlnode *node, *child;
155 144
156 static void 145 name = (const char *)key;
157 blist_print_buddy_settings(gpointer key, gpointer data, 146 data = (const char *)value;
158 gpointer user_data) 147 node = (xmlnode *)user_data;
159 { 148
160 blist_print_setting(key, data, user_data, 5); 149 child = xmlnode_new_child(node, "component");
161 } 150 xmlnode_set_attrib(child, "name", name);
162 151 xmlnode_insert_data(child, data, -1);
163 static void 152 }
164 blist_print_cnode_settings(gpointer key, gpointer data, 153
165 gpointer user_data) 154 xmlnode *
166 { 155 buddy_to_xmlnode(GaimBlistNode *bnode)
167 blist_print_setting(key, data, user_data, 4); 156 {
168 } 157 xmlnode *node, *child;
169 158 GaimBuddy *buddy;
170 static void 159
171 blist_print_chat_components(gpointer key, gpointer data, 160 buddy = (GaimBuddy *)bnode;
172 gpointer user_data) 161
173 { 162 node = xmlnode_new("buddy");
174 char *key_val; 163 xmlnode_set_attrib(node, "account", gaim_account_get_username(buddy->account));
175 char *data_val; 164 xmlnode_set_attrib(node, "proto", gaim_account_get_protocol_id(buddy->account));
176 FILE *file = user_data; 165
177 166 child = xmlnode_new_child(node, "name");
178 if (!key || !data) 167 xmlnode_insert_data(child, buddy->name, -1);
179 return; 168
180 169 if (buddy->alias != NULL)
181 key_val = g_markup_escape_text(key, -1); 170 {
182 data_val = g_markup_escape_text(data, -1); 171 child = xmlnode_new_child(node, "alias");
183 172 xmlnode_insert_data(child, buddy->alias, -1);
184 fprintf(file, "\t\t\t\t<component name=\"%s\">%s</component>\n", key_val, 173 }
185 data_val); 174
186 g_free(key_val); 175 /* Write buddy settings */
187 g_free(data_val); 176 g_hash_table_foreach(buddy->node.settings, setting_to_xmlnode, node);
188 } 177
189 178 return node;
190 static void 179 }
191 print_buddy(FILE *file, GaimBuddy *buddy) 180
192 { 181 xmlnode *
193 char *bud_name = g_markup_escape_text(buddy->name, -1); 182 contact_to_xmlnode(GaimBlistNode *cnode)
194 char *bud_alias = NULL; 183 {
195 char *acct_name = g_markup_escape_text(buddy->account->username, -1); 184 xmlnode *node, *child;
196 if (buddy->alias) 185 GaimContact *contact;
197 bud_alias= g_markup_escape_text(buddy->alias, -1); 186 GaimBlistNode *bnode;
198 fprintf(file, "\t\t\t\t<buddy account=\"%s\" proto=\"%s\">\n", acct_name, 187
199 gaim_account_get_protocol_id(buddy->account)); 188 contact = (GaimContact *)cnode;
200 189
201 fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name); 190 node = xmlnode_new("contact");
202 if (bud_alias) { 191
203 fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n", bud_alias); 192 if (contact->alias != NULL)
204 } 193 {
205 g_hash_table_foreach(buddy->node.settings, blist_print_buddy_settings, file); 194 xmlnode_set_attrib(node, "alias", contact->alias);
206 fprintf(file, "\t\t\t\t</buddy>\n"); 195 }
207 g_free(bud_name); 196
208 g_free(bud_alias); 197 /* Write buddies */
209 g_free(acct_name); 198 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
210 } 199 {
211 200 if (!GAIM_BLIST_NODE_SHOULD_SAVE(bnode))
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; 201 continue;
244 202 if (GAIM_BLIST_NODE_IS_BUDDY(bnode))
245 if (blist_buddy_should_save(exp_acct, (GaimBuddy *) bnode)) 203 {
246 return TRUE; 204 child = buddy_to_xmlnode(bnode);
247 } 205 xmlnode_insert_child(node, child);
248 206 }
249 return FALSE; 207 }
250 } 208
251 209 /* Write contact settings */
252 static void 210 g_hash_table_foreach(cnode->settings, setting_to_xmlnode, node);
253 blist_write_contact(FILE *file, GaimAccount *exp_acct, GaimContact *contact) 211
254 { 212 return node;
255 GaimBlistNode *bnode, *cnode = (GaimBlistNode *) contact; 213 }
256 214
257 if (!blist_contact_should_save(exp_acct, contact)) 215 xmlnode *
258 return; 216 chat_to_xmlnode(GaimBlistNode *cnode)
259 217 {
260 fprintf(file, "\t\t\t<contact"); 218 xmlnode *node, *child;
261 if (contact->alias) { 219 GaimChat *chat;
262 char *alias = g_markup_escape_text(contact->alias, -1); 220
263 fprintf(file, " alias=\"%s\"", alias); 221 chat = (GaimChat *)cnode;
264 g_free(alias); 222
265 } 223 node = xmlnode_new("chat");
266 fprintf(file, ">\n"); 224 xmlnode_set_attrib(node, "proto", gaim_account_get_protocol_id(chat->account));
267 225 xmlnode_set_attrib(node, "account", gaim_account_get_username(chat->account));
268 for (bnode = cnode->child; bnode; bnode = bnode->next) { 226
269 if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) { 227 if (chat->alias != NULL)
270 blist_write_buddy(file, exp_acct, (GaimBuddy *) bnode); 228 {
271 } 229 child = xmlnode_new_child(node, "alias");
272 } 230 xmlnode_insert_data(child, chat->alias, -1);
273 231 }
274 g_hash_table_foreach(cnode->settings, blist_print_cnode_settings, file); 232
275 fprintf(file, "\t\t\t</contact>\n"); 233 /* Write chat components */
276 } 234 g_hash_table_foreach(chat->components, chat_component_to_xmlnode, node);
277 235
278 static void 236 /* Write chat settings */
279 blist_write_chat(FILE *file, GaimAccount *exp_acct, GaimChat *chat) 237 g_hash_table_foreach(chat->node.settings, setting_to_xmlnode, node);
280 { 238
281 char *acct_name; 239 return node;
282 240 }
283 if (! GAIM_BLIST_NODE_SHOULD_SAVE((GaimBlistNode *) chat)) 241
284 return; 242 xmlnode *
285 243 group_to_xmlnode(GaimBlistNode *gnode)
286 if (exp_acct && chat->account != exp_acct) 244 {
287 return; 245 xmlnode *node, *child;
288 246 GaimGroup *group;
289 acct_name = g_markup_escape_text(chat->account->username, -1); 247 GaimBlistNode *cnode;
290 fprintf(file, "\t\t\t<chat proto=\"%s\" account=\"%s\">\n", 248
291 gaim_account_get_protocol_id(chat->account), acct_name); 249 group = (GaimGroup *)gnode;
292 g_free(acct_name); 250
293 251 node = xmlnode_new("group");
294 if (chat->alias) { 252 xmlnode_set_attrib(node, "name", group->name);
295 char *chat_alias = g_markup_escape_text(chat->alias, -1); 253
296 fprintf(file, "\t\t\t\t<alias>%s</alias>\n", chat_alias); 254 /* Write settings */
297 g_free(chat_alias); 255 g_hash_table_foreach(group->node.settings, setting_to_xmlnode, node);
298 } 256
299 257 /* Write contacts and chats */
300 g_hash_table_foreach(chat->components, blist_print_chat_components, file); 258 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
301 g_hash_table_foreach(chat->node.settings, blist_print_cnode_settings, file); 259 {
302 260 if (!GAIM_BLIST_NODE_SHOULD_SAVE(cnode))
303 fprintf(file, "\t\t\t</chat>\n"); 261 continue;
304 } 262 if (GAIM_BLIST_NODE_IS_CONTACT(cnode))
305 263 {
306 static void 264 child = contact_to_xmlnode(cnode);
307 blist_write_group(FILE *file, GaimAccount *exp_acct, GaimGroup *group) 265 xmlnode_insert_child(node, child);
308 { 266 }
309 GaimBlistNode *cnode, *gnode = (GaimBlistNode *) group; 267 else if (GAIM_BLIST_NODE_IS_CHAT(cnode))
310 char *group_name; 268 {
311 269 child = chat_to_xmlnode(cnode);
312 if (! GAIM_BLIST_NODE_SHOULD_SAVE(gnode)) 270 xmlnode_insert_child(node, child);
313 return; 271 }
314 272 }
315 if (exp_acct && ! gaim_group_on_account(group, exp_acct)) 273
316 return; 274 return node;
317 275 }
318 group_name = g_markup_escape_text(group->name, -1); 276
319 fprintf(file, "\t\t<group name=\"%s\">\n", group_name); 277 xmlnode *
320 g_free(group_name); 278 accountprivacy_to_xmlnode(GaimAccount *account)
321 279 {
322 g_hash_table_foreach(group->node.settings, 280 xmlnode *node, *child;
323 blist_print_group_settings, file); 281 GSList *cur;
324 282 char buf[10];
325 for (cnode = gnode->child; cnode; cnode = cnode->next) { 283
326 if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) { 284 node = xmlnode_new("account");
327 blist_write_contact(file, exp_acct, (GaimContact *) cnode); 285 xmlnode_set_attrib(node, "proto", gaim_account_get_protocol_id(account));
328 } else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) { 286 xmlnode_set_attrib(node, "name", gaim_account_get_username(account));
329 blist_write_chat(file, exp_acct, (GaimChat *) cnode); 287 snprintf(buf, sizeof(buf), "%d", account->perm_deny);
330 } 288 xmlnode_set_attrib(node, "mode", buf);
331 } 289
332 290 for (cur = account->permit; cur; cur = cur->next)
333 fprintf(file, "\t\t</group>\n"); 291 {
334 } 292 child = xmlnode_new_child(node, "permit");
335 293 xmlnode_insert_data(child, cur->data, -1);
336 static void 294 }
337 blist_write_privacy_account(FILE *file, GaimAccount *exp_acct, GaimAccount *account) 295
338 { 296 for (cur = account->deny; cur; cur = cur->next)
339 char *acct_name; 297 {
340 GSList *buds; 298 child = xmlnode_new_child(node, "block");
341 299 xmlnode_insert_data(child, cur->data, -1);
342 if(exp_acct && exp_acct != account) 300 }
343 return; 301
344 302 return node;
345 acct_name = g_markup_escape_text(account->username, -1); 303 }
346 fprintf(file, "\t\t<account proto=\"%s\" name=\"%s\" mode=\"%d\">\n", 304
347 gaim_account_get_protocol_id(account), 305 xmlnode *
348 acct_name, account->perm_deny); 306 blist_to_xmlnode()
349 g_free(acct_name); 307 {
350 308 xmlnode *node, *child, *grandchild;
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; 309 GaimBlistNode *gnode;
371 310 GList *cur;
372 fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n\n"); 311
373 fprintf(file, "<gaim version='1.0'>\n"); 312 node = xmlnode_new("gaim");
374 fprintf(file, "\t<blist>\n"); 313 xmlnode_set_attrib(node, "version", "1.0");
375 314
376 for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) { 315 /* Write groups */
316 child = xmlnode_new_child(node, "blist");
317 for (gnode = gaimbuddylist->root; gnode != NULL; gnode = gnode->next)
318 {
319 if (!GAIM_BLIST_NODE_SHOULD_SAVE(gnode))
320 continue;
377 if (GAIM_BLIST_NODE_IS_GROUP(gnode)) 321 if (GAIM_BLIST_NODE_IS_GROUP(gnode))
378 blist_write_group(file, exp_acct, (GaimGroup *) gnode); 322 {
379 } 323 grandchild = group_to_xmlnode(gnode);
380 324 xmlnode_insert_child(child, grandchild);
381 fprintf(file, "\t</blist>\n"); 325 }
382 fprintf(file, "\t<privacy>\n"); 326 }
383 327
384 for (accounts = gaim_accounts_get_all(); accounts; accounts = accounts->next) { 328 /* Write privacy settings */
385 blist_write_privacy_account(file, exp_acct, (GaimAccount *) accounts->data); 329 child = xmlnode_new_child(node, "privacy");
386 } 330 for (cur = gaim_accounts_get_all(); cur != NULL; cur = cur->next)
387 331 {
388 fprintf(file, "\t</privacy>\n"); 332 grandchild = accountprivacy_to_xmlnode(cur->data);
389 fprintf(file, "</gaim>\n"); 333 xmlnode_insert_child(child, grandchild);
334 }
335
336 return node;
390 } 337 }
391 338
392 void 339 void
393 gaim_blist_sync() 340 gaim_blist_sync()
394 { 341 {
395 FILE *file; 342 xmlnode *node;
396 struct stat st; 343 char *data;
397 const char *user_dir = gaim_user_dir(); 344
398 char *filename; 345 if (!blist_loaded)
399 char *filename_real; 346 {
400 347 gaim_debug_error("blist", "Attempted to save buddy list before it "
401 g_return_if_fail(user_dir != NULL); 348 "was read!\n");
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; 349 return;
407 } 350 }
408 351
409 if (!g_file_test(user_dir, G_FILE_TEST_IS_DIR)) 352 node = blist_to_xmlnode();
410 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); 353 data = xmlnode_to_formatted_str(node, NULL);
411 354 gaim_util_write_data_to_file("blist.xml", data, -1);
412 filename = g_build_filename(user_dir, "blist.xml.save", NULL); 355 g_free(data);
413 356 xmlnode_free(node);
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 } 357 }
440 358
441 static gboolean 359 static gboolean
442 save_cb(gpointer data) 360 save_cb(gpointer data)
443 { 361 {