| 232 |
232 |
| 233 /********************************************************************* |
233 /********************************************************************* |
| 234 * Writing to disk * |
234 * Writing to disk * |
| 235 *********************************************************************/ |
235 *********************************************************************/ |
| 236 |
236 |
| 237 static xmlnode * |
237 static PurpleXmlNode * |
| 238 substatus_to_xmlnode(PurpleSavedStatusSub *substatus) |
238 substatus_to_xmlnode(PurpleSavedStatusSub *substatus) |
| 239 { |
239 { |
| 240 xmlnode *node, *child; |
240 PurpleXmlNode *node, *child; |
| 241 |
241 |
| 242 node = xmlnode_new("substatus"); |
242 node = purple_xmlnode_new("substatus"); |
| 243 |
243 |
| 244 child = xmlnode_new_child(node, "account"); |
244 child = purple_xmlnode_new_child(node, "account"); |
| 245 xmlnode_set_attrib(child, "protocol", purple_account_get_protocol_id(substatus->account)); |
245 purple_xmlnode_set_attrib(child, "protocol", purple_account_get_protocol_id(substatus->account)); |
| 246 xmlnode_insert_data(child, |
246 purple_xmlnode_insert_data(child, |
| 247 purple_normalize(substatus->account, |
247 purple_normalize(substatus->account, |
| 248 purple_account_get_username(substatus->account)), -1); |
248 purple_account_get_username(substatus->account)), -1); |
| 249 |
249 |
| 250 child = xmlnode_new_child(node, "state"); |
250 child = purple_xmlnode_new_child(node, "state"); |
| 251 xmlnode_insert_data(child, purple_status_type_get_id(substatus->type), -1); |
251 purple_xmlnode_insert_data(child, purple_status_type_get_id(substatus->type), -1); |
| 252 |
252 |
| 253 if (substatus->message != NULL) |
253 if (substatus->message != NULL) |
| 254 { |
254 { |
| 255 child = xmlnode_new_child(node, "message"); |
255 child = purple_xmlnode_new_child(node, "message"); |
| 256 xmlnode_insert_data(child, substatus->message, -1); |
256 purple_xmlnode_insert_data(child, substatus->message, -1); |
| 257 } |
257 } |
| 258 |
258 |
| 259 return node; |
259 return node; |
| 260 } |
260 } |
| 261 |
261 |
| 262 static xmlnode * |
262 static PurpleXmlNode * |
| 263 status_to_xmlnode(PurpleSavedStatus *status) |
263 status_to_xmlnode(PurpleSavedStatus *status) |
| 264 { |
264 { |
| 265 xmlnode *node, *child; |
265 PurpleXmlNode *node, *child; |
| 266 char buf[21]; |
266 char buf[21]; |
| 267 GList *cur; |
267 GList *cur; |
| 268 |
268 |
| 269 node = xmlnode_new("status"); |
269 node = purple_xmlnode_new("status"); |
| 270 if (status->title != NULL) |
270 if (status->title != NULL) |
| 271 { |
271 { |
| 272 xmlnode_set_attrib(node, "name", status->title); |
272 purple_xmlnode_set_attrib(node, "name", status->title); |
| 273 } |
273 } |
| 274 else |
274 else |
| 275 { |
275 { |
| 276 /* |
276 /* |
| 277 * Purple 1.5.0 and earlier require a name to be set, so we |
277 * Purple 1.5.0 and earlier require a name to be set, so we |
| 279 * in the status.xml file. Eventually this should be removed |
279 * in the status.xml file. Eventually this should be removed |
| 280 * and we should determine if a status is transient by |
280 * and we should determine if a status is transient by |
| 281 * whether the "name" attribute is set to something or if |
281 * whether the "name" attribute is set to something or if |
| 282 * it does not exist at all. |
282 * it does not exist at all. |
| 283 */ |
283 */ |
| 284 xmlnode_set_attrib(node, "name", "Auto-Cached"); |
284 purple_xmlnode_set_attrib(node, "name", "Auto-Cached"); |
| 285 xmlnode_set_attrib(node, "transient", "true"); |
285 purple_xmlnode_set_attrib(node, "transient", "true"); |
| 286 } |
286 } |
| 287 |
287 |
| 288 g_snprintf(buf, sizeof(buf), "%lu", status->creation_time); |
288 g_snprintf(buf, sizeof(buf), "%lu", status->creation_time); |
| 289 xmlnode_set_attrib(node, "created", buf); |
289 purple_xmlnode_set_attrib(node, "created", buf); |
| 290 |
290 |
| 291 g_snprintf(buf, sizeof(buf), "%lu", status->lastused); |
291 g_snprintf(buf, sizeof(buf), "%lu", status->lastused); |
| 292 xmlnode_set_attrib(node, "lastused", buf); |
292 purple_xmlnode_set_attrib(node, "lastused", buf); |
| 293 |
293 |
| 294 g_snprintf(buf, sizeof(buf), "%u", status->usage_count); |
294 g_snprintf(buf, sizeof(buf), "%u", status->usage_count); |
| 295 xmlnode_set_attrib(node, "usage_count", buf); |
295 purple_xmlnode_set_attrib(node, "usage_count", buf); |
| 296 |
296 |
| 297 child = xmlnode_new_child(node, "state"); |
297 child = purple_xmlnode_new_child(node, "state"); |
| 298 xmlnode_insert_data(child, purple_primitive_get_id_from_type(status->type), -1); |
298 purple_xmlnode_insert_data(child, purple_primitive_get_id_from_type(status->type), -1); |
| 299 |
299 |
| 300 if (status->message != NULL) |
300 if (status->message != NULL) |
| 301 { |
301 { |
| 302 child = xmlnode_new_child(node, "message"); |
302 child = purple_xmlnode_new_child(node, "message"); |
| 303 xmlnode_insert_data(child, status->message, -1); |
303 purple_xmlnode_insert_data(child, status->message, -1); |
| 304 } |
304 } |
| 305 |
305 |
| 306 for (cur = status->substatuses; cur != NULL; cur = cur->next) |
306 for (cur = status->substatuses; cur != NULL; cur = cur->next) |
| 307 { |
307 { |
| 308 child = substatus_to_xmlnode(cur->data); |
308 child = substatus_to_xmlnode(cur->data); |
| 309 xmlnode_insert_child(node, child); |
309 purple_xmlnode_insert_child(node, child); |
| 310 } |
310 } |
| 311 |
311 |
| 312 return node; |
312 return node; |
| 313 } |
313 } |
| 314 |
314 |
| 315 static xmlnode * |
315 static PurpleXmlNode * |
| 316 statuses_to_xmlnode(void) |
316 statuses_to_xmlnode(void) |
| 317 { |
317 { |
| 318 xmlnode *node, *child; |
318 PurpleXmlNode *node, *child; |
| 319 GList *cur; |
319 GList *cur; |
| 320 |
320 |
| 321 node = xmlnode_new("statuses"); |
321 node = purple_xmlnode_new("statuses"); |
| 322 xmlnode_set_attrib(node, "version", "1.0"); |
322 purple_xmlnode_set_attrib(node, "version", "1.0"); |
| 323 |
323 |
| 324 for (cur = saved_statuses; cur != NULL; cur = cur->next) |
324 for (cur = saved_statuses; cur != NULL; cur = cur->next) |
| 325 { |
325 { |
| 326 child = status_to_xmlnode(cur->data); |
326 child = status_to_xmlnode(cur->data); |
| 327 xmlnode_insert_child(node, child); |
327 purple_xmlnode_insert_child(node, child); |
| 328 } |
328 } |
| 329 |
329 |
| 330 return node; |
330 return node; |
| 331 } |
331 } |
| 332 |
332 |
| 333 static void |
333 static void |
| 334 sync_statuses(void) |
334 sync_statuses(void) |
| 335 { |
335 { |
| 336 xmlnode *node; |
336 PurpleXmlNode *node; |
| 337 char *data; |
337 char *data; |
| 338 |
338 |
| 339 if (!statuses_loaded) |
339 if (!statuses_loaded) |
| 340 { |
340 { |
| 341 purple_debug_error("status", "Attempted to save statuses before they " |
341 purple_debug_error("status", "Attempted to save statuses before they " |
| 342 "were read!\n"); |
342 "were read!\n"); |
| 343 return; |
343 return; |
| 344 } |
344 } |
| 345 |
345 |
| 346 node = statuses_to_xmlnode(); |
346 node = statuses_to_xmlnode(); |
| 347 data = xmlnode_to_formatted_str(node, NULL); |
347 data = purple_xmlnode_to_formatted_str(node, NULL); |
| 348 purple_util_write_data_to_file("status.xml", data, -1); |
348 purple_util_write_data_to_file("status.xml", data, -1); |
| 349 g_free(data); |
349 g_free(data); |
| 350 xmlnode_free(node); |
350 purple_xmlnode_free(node); |
| 351 } |
351 } |
| 352 |
352 |
| 353 static gboolean |
353 static gboolean |
| 354 save_cb(gpointer data) |
354 save_cb(gpointer data) |
| 355 { |
355 { |
| 369 /********************************************************************* |
369 /********************************************************************* |
| 370 * Reading from disk * |
370 * Reading from disk * |
| 371 *********************************************************************/ |
371 *********************************************************************/ |
| 372 |
372 |
| 373 static PurpleSavedStatusSub * |
373 static PurpleSavedStatusSub * |
| 374 parse_substatus(xmlnode *substatus) |
374 parse_substatus(PurpleXmlNode *substatus) |
| 375 { |
375 { |
| 376 PurpleSavedStatusSub *ret; |
376 PurpleSavedStatusSub *ret; |
| 377 xmlnode *node; |
377 PurpleXmlNode *node; |
| 378 char *data; |
378 char *data; |
| 379 |
379 |
| 380 ret = g_new0(PurpleSavedStatusSub, 1); |
380 ret = g_new0(PurpleSavedStatusSub, 1); |
| 381 |
381 |
| 382 /* Read the account */ |
382 /* Read the account */ |
| 383 node = xmlnode_get_child(substatus, "account"); |
383 node = purple_xmlnode_get_child(substatus, "account"); |
| 384 if (node != NULL) |
384 if (node != NULL) |
| 385 { |
385 { |
| 386 char *acct_name; |
386 char *acct_name; |
| 387 const char *protocol; |
387 const char *protocol; |
| 388 acct_name = xmlnode_get_data(node); |
388 acct_name = purple_xmlnode_get_data(node); |
| 389 protocol = xmlnode_get_attrib(node, "protocol"); |
389 protocol = purple_xmlnode_get_attrib(node, "protocol"); |
| 390 if ((acct_name != NULL) && (protocol != NULL)) |
390 if ((acct_name != NULL) && (protocol != NULL)) |
| 391 ret->account = purple_accounts_find(acct_name, protocol); |
391 ret->account = purple_accounts_find(acct_name, protocol); |
| 392 g_free(acct_name); |
392 g_free(acct_name); |
| 393 } |
393 } |
| 394 |
394 |
| 447 * </status> |
447 * </status> |
| 448 * |
448 * |
| 449 * I know. Moving, huh? |
449 * I know. Moving, huh? |
| 450 */ |
450 */ |
| 451 static PurpleSavedStatus * |
451 static PurpleSavedStatus * |
| 452 parse_status(xmlnode *status) |
452 parse_status(PurpleXmlNode *status) |
| 453 { |
453 { |
| 454 PurpleSavedStatus *ret; |
454 PurpleSavedStatus *ret; |
| 455 xmlnode *node; |
455 PurpleXmlNode *node; |
| 456 const char *attrib; |
456 const char *attrib; |
| 457 char *data; |
457 char *data; |
| 458 int i; |
458 int i; |
| 459 |
459 |
| 460 ret = g_new0(PurpleSavedStatus, 1); |
460 ret = g_new0(PurpleSavedStatus, 1); |
| 461 |
461 |
| 462 attrib = xmlnode_get_attrib(status, "transient"); |
462 attrib = purple_xmlnode_get_attrib(status, "transient"); |
| 463 if (!purple_strequal(attrib, "true")) |
463 if (!purple_strequal(attrib, "true")) |
| 464 { |
464 { |
| 465 /* Read the title */ |
465 /* Read the title */ |
| 466 attrib = xmlnode_get_attrib(status, "name"); |
466 attrib = purple_xmlnode_get_attrib(status, "name"); |
| 467 ret->title = g_strdup(attrib); |
467 ret->title = g_strdup(attrib); |
| 468 } |
468 } |
| 469 |
469 |
| 470 if (ret->title != NULL) |
470 if (ret->title != NULL) |
| 471 { |
471 { |
| 478 i++; |
478 i++; |
| 479 } |
479 } |
| 480 } |
480 } |
| 481 |
481 |
| 482 /* Read the creation time */ |
482 /* Read the creation time */ |
| 483 attrib = xmlnode_get_attrib(status, "created"); |
483 attrib = purple_xmlnode_get_attrib(status, "created"); |
| 484 set_creation_time(ret, (attrib != NULL ? atol(attrib) : 0)); |
484 set_creation_time(ret, (attrib != NULL ? atol(attrib) : 0)); |
| 485 |
485 |
| 486 /* Read the last used time */ |
486 /* Read the last used time */ |
| 487 attrib = xmlnode_get_attrib(status, "lastused"); |
487 attrib = purple_xmlnode_get_attrib(status, "lastused"); |
| 488 ret->lastused = (attrib != NULL ? atol(attrib) : 0); |
488 ret->lastused = (attrib != NULL ? atol(attrib) : 0); |
| 489 |
489 |
| 490 /* Read the usage count */ |
490 /* Read the usage count */ |
| 491 attrib = xmlnode_get_attrib(status, "usage_count"); |
491 attrib = purple_xmlnode_get_attrib(status, "usage_count"); |
| 492 ret->usage_count = (attrib != NULL ? atol(attrib) : 0); |
492 ret->usage_count = (attrib != NULL ? atol(attrib) : 0); |
| 493 |
493 |
| 494 /* Read the primitive status type */ |
494 /* Read the primitive status type */ |
| 495 node = xmlnode_get_child(status, "state"); |
495 node = purple_xmlnode_get_child(status, "state"); |
| 496 if ((node != NULL) && ((data = xmlnode_get_data(node)) != NULL)) |
496 if ((node != NULL) && ((data = purple_xmlnode_get_data(node)) != NULL)) |
| 497 { |
497 { |
| 498 ret->type = purple_primitive_get_type_from_id(data); |
498 ret->type = purple_primitive_get_type_from_id(data); |
| 499 g_free(data); |
499 g_free(data); |
| 500 } |
500 } |
| 501 |
501 |
| 502 /* Read the message */ |
502 /* Read the message */ |
| 503 node = xmlnode_get_child(status, "message"); |
503 node = purple_xmlnode_get_child(status, "message"); |
| 504 if ((node != NULL) && ((data = xmlnode_get_data(node)) != NULL)) |
504 if ((node != NULL) && ((data = purple_xmlnode_get_data(node)) != NULL)) |
| 505 { |
505 { |
| 506 ret->message = data; |
506 ret->message = data; |
| 507 } |
507 } |
| 508 |
508 |
| 509 /* Read substatuses */ |
509 /* Read substatuses */ |
| 510 for (node = xmlnode_get_child(status, "substatus"); node != NULL; |
510 for (node = purple_xmlnode_get_child(status, "substatus"); node != NULL; |
| 511 node = xmlnode_get_next_twin(node)) |
511 node = purple_xmlnode_get_next_twin(node)) |
| 512 { |
512 { |
| 513 PurpleSavedStatusSub *new; |
513 PurpleSavedStatusSub *new; |
| 514 new = parse_substatus(node); |
514 new = parse_substatus(node); |
| 515 if (new != NULL) |
515 if (new != NULL) |
| 516 ret->substatuses = g_list_prepend(ret->substatuses, new); |
516 ret->substatuses = g_list_prepend(ret->substatuses, new); |
| 527 * be opened, or if it contains invalid XML). |
527 * be opened, or if it contains invalid XML). |
| 528 */ |
528 */ |
| 529 static void |
529 static void |
| 530 load_statuses(void) |
530 load_statuses(void) |
| 531 { |
531 { |
| 532 xmlnode *statuses, *status; |
532 PurpleXmlNode *statuses, *status; |
| 533 |
533 |
| 534 statuses_loaded = TRUE; |
534 statuses_loaded = TRUE; |
| 535 |
535 |
| 536 statuses = purple_util_read_xml_from_file("status.xml", _("saved statuses")); |
536 statuses = purple_util_read_xml_from_file("status.xml", _("saved statuses")); |
| 537 |
537 |
| 538 if (statuses == NULL) |
538 if (statuses == NULL) |
| 539 return; |
539 return; |
| 540 |
540 |
| 541 for (status = xmlnode_get_child(statuses, "status"); status != NULL; |
541 for (status = purple_xmlnode_get_child(statuses, "status"); status != NULL; |
| 542 status = xmlnode_get_next_twin(status)) |
542 status = purple_xmlnode_get_next_twin(status)) |
| 543 { |
543 { |
| 544 PurpleSavedStatus *new; |
544 PurpleSavedStatus *new; |
| 545 new = parse_status(status); |
545 new = parse_status(status); |
| 546 saved_statuses = g_list_prepend(saved_statuses, new); |
546 saved_statuses = g_list_prepend(saved_statuses, new); |
| 547 } |
547 } |
| 548 saved_statuses = g_list_sort(saved_statuses, saved_statuses_sort_func); |
548 saved_statuses = g_list_sort(saved_statuses, saved_statuses_sort_func); |
| 549 |
549 |
| 550 xmlnode_free(statuses); |
550 purple_xmlnode_free(statuses); |
| 551 } |
551 } |
| 552 |
552 |
| 553 |
553 |
| 554 /************************************************************************** |
554 /************************************************************************** |
| 555 * Saved status API |
555 * Saved status API |