about.c: cosmetix
[k8lowj.git] / src / livejournal.c
blobfd8a1cb40b9f628945ffb5b436e8136f6bae5f99
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 #include "glib-all.h"
8 #include <string.h>
9 #include "liblj/editpostevent.h"
10 #include "jamdoc.h"
11 #include "account.h"
12 #include "jam_xml.h"
13 #include "conf_xml.h"
14 #include "network.h"
15 #include "util.h"
17 struct _JamHostLJ {
18 JamHost host;
19 LJServer *server;
22 JamAccount*
23 jam_account_lj_new(LJServer *server, const char *username) {
24 JamAccountLJ *acc;
26 acc = JAM_ACCOUNT_LJ(g_object_new(jam_account_lj_get_type(), NULL));
27 acc->user = lj_user_new(server);
28 if (username)
29 acc->user->username = g_strdup(username);
31 return JAM_ACCOUNT(acc);
34 static GSList*
35 parsepickws(xmlDocPtr doc, xmlNodePtr node) {
36 GSList *pickws = NULL;
37 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
38 XML_GET_LIST("pickw", pickws, jam_xmlGetString)
39 XML_GET_END("parsepickws")
41 return pickws;
44 static GSList*
45 parseusejournals(xmlDocPtr doc, xmlNodePtr node) {
46 GSList *l = NULL;
47 char *journal;
48 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
49 if (xmlStrcmp(node->name, BAD_CAST "usejournal") == 0) {
50 journal = jam_xmlGetString(doc, node);
51 l = g_slist_append(l, journal);
52 } else
53 XML_GET_END("usejournals")
55 return l;
58 static GSList*
59 parsefriendgroups(xmlDocPtr doc, xmlNodePtr node) {
60 GSList *fgs = NULL;
61 int id;
62 LJFriendGroup *fg;
63 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
64 if (xmlStrcmp(node->name, BAD_CAST "friendgroup") == 0) {
65 if (jam_xmlGetIntProp(node, "id", &id)) {
66 fg = lj_friendgroup_new();
68 fg->id = id;
69 fg->name = jam_xmlGetString(doc, node);
70 jam_xmlGetIntProp(node, "ispublic", &fg->ispublic);
71 fgs = g_slist_append(fgs, fg);
73 } else
74 XML_GET_END("parsefriendgroups")
76 return fgs;
79 static GSList*
80 parsewebmenu(xmlDocPtr doc, xmlNodePtr node) {
81 GSList *webmenu = NULL;
82 LJWebMenuItem *wmi;
83 xmlChar *text, *url;
85 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
86 if (xmlStrcmp(node->name, BAD_CAST "menuitem") == 0) {
87 wmi = lj_webmenuitem_new();
88 if ((text = xmlGetProp(node, BAD_CAST "text"))) {
89 wmi->text = g_strdup((char*)text);
90 if ((url = xmlGetProp(node, BAD_CAST "url"))) {
91 wmi->url = g_strdup((char*)url);
92 xmlFree(url);
94 xmlFree(text);
96 if (node->xmlChildrenNode)
97 wmi->subitems = parsewebmenu(doc, node);
98 webmenu = g_slist_append(webmenu, wmi);
99 } else
100 XML_GET_END("parsewebmenu")
102 return webmenu;
105 static void
106 writewebmenu(xmlNodePtr parent, GSList *webmenu) {
107 GSList *l;
108 xmlNodePtr node;
109 LJWebMenuItem *wmi;
111 for (l = webmenu; l != NULL; l = l->next) {
112 wmi = (LJWebMenuItem*)l->data;
113 node = xmlNewChild(parent, NULL, BAD_CAST "menuitem", NULL);
114 if (wmi->text)
115 xmlSetProp(node, BAD_CAST "text", BAD_CAST wmi->text);
116 if (wmi->url)
117 xmlSetProp(node, BAD_CAST "url", BAD_CAST wmi->url);
118 if (wmi->subitems)
119 writewebmenu(node, wmi->subitems);
123 void
124 jam_account_lj_write(JamAccountLJ *account, xmlNodePtr node) {
125 LJUser *user = account->user;
126 xmlNodePtr xmlList, child;
127 GSList *l;
128 char buf[10];
129 LJFriendGroup *fg;
131 if (user->fullname)
132 xmlNewTextChild(node, NULL,
133 BAD_CAST "fullname", BAD_CAST user->fullname);
135 if (account->lastupdate)
136 jam_xmlAddInt(node, "lastupdate", (int)account->lastupdate);
137 if (user->checkfriends)
138 jam_xmlAddInt(node, "checkfriends", (int)TRUE);
139 if (account->cfmask) {
140 g_snprintf(buf, 10, "%d", account->cfmask);
141 xmlNewTextChild(node, NULL, BAD_CAST "cfmask", BAD_CAST buf);
144 if (user->pickws) {
145 xmlList = xmlNewChild(node, NULL, BAD_CAST "pickws", NULL);
146 for (l = user->pickws; l != NULL; l = l->next) {
147 xmlNewTextChild(xmlList, NULL, BAD_CAST "pickw", BAD_CAST l->data);
151 if (user->usejournals) {
152 xmlList = xmlNewChild(node, NULL, BAD_CAST "usejournals", NULL);
153 for (l = user->usejournals; l != NULL; l = l->next) {
154 xmlNewTextChild(xmlList, NULL, BAD_CAST "usejournal", BAD_CAST l->data);
158 if (user->friendgroups) {
159 xmlList = xmlNewChild(node, NULL, BAD_CAST "friendgroups", NULL);
160 for (l = user->friendgroups; l != NULL; l = l->next) {
161 fg = (LJFriendGroup*)l->data;
162 child = xmlNewTextChild(xmlList, NULL,
163 BAD_CAST "friendgroup", BAD_CAST fg->name);
164 g_snprintf(buf, 10, "%d", fg->id);
165 xmlSetProp(child, BAD_CAST "id", BAD_CAST buf);
166 g_snprintf(buf, 10, "%d", fg->ispublic);
167 xmlSetProp(child, BAD_CAST "ispublic", BAD_CAST buf);
171 if (user->webmenu) {
172 xmlList = xmlNewChild(node, NULL, BAD_CAST "webmenu", NULL);
173 writewebmenu(xmlList, user->webmenu);
178 JamAccount*
179 jam_account_lj_from_xml(xmlDocPtr doc, xmlNodePtr node, JamHostLJ *host) {
180 JamAccount *account;
181 JamAccountLJ *accountlj;
182 LJUser *user;
183 guint32 lastupdate = 0;
185 account = jam_account_lj_new(jam_host_lj_get_server(host), NULL);
186 accountlj = JAM_ACCOUNT_LJ(account);
187 user = accountlj->user;
188 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
189 XML_GET_STR("username", user->username)
190 XML_GET_STR("fullname", user->fullname)
191 XML_GET_STR("password", user->password)
192 XML_GET_BOOL("checkfriends", user->checkfriends)
193 XML_GET_UINT32("lastupdate", lastupdate)
194 XML_GET_FUNC("pickws", user->pickws, parsepickws)
195 XML_GET_FUNC("usejournals", user->usejournals, parseusejournals)
196 XML_GET_FUNC("friendgroups", user->friendgroups, parsefriendgroups)
197 XML_GET_FUNC("webmenu", user->webmenu, parsewebmenu)
198 XML_GET_UINT32("cfmask", accountlj->cfmask)
199 XML_GET_END("jam_account_lj_from_xml")
202 accountlj->lastupdate = (time_t)lastupdate;
204 return account;
207 const gchar*
208 jam_account_lj_get_username(JamAccount *acc) {
209 return JAM_ACCOUNT_LJ(acc)->user->username;
212 const gchar*
213 jam_account_lj_get_password(JamAccount *acc) {
214 return JAM_ACCOUNT_LJ(acc)->user->password;
217 gboolean
218 jam_account_lj_get_checkfriends(JamAccount *acc) {
219 return JAM_ACCOUNT_LJ(acc)->user->checkfriends;
222 static void
223 jam_account_lj_set_password(JamAccount *acc, const char *password) {
224 string_replace(&JAM_ACCOUNT_LJ(acc)->user->password, g_strdup(password));
227 LJUser*
228 jam_account_lj_get_user(JamAccountLJ *acc) {
229 return acc->user;
232 LJServer*
233 jam_account_lj_get_server(JamAccountLJ *acc) {
234 return acc->user->server;
237 guint32
238 jam_account_lj_get_cfmask(JamAccountLJ *acc) {
239 return acc->cfmask;
242 void
243 jam_account_lj_set_cfmask(JamAccountLJ *acc, guint32 mask) {
244 acc->cfmask = mask;
247 static void
248 jam_account_lj_class_init(JamAccountClass *klass) {
249 klass->get_username = jam_account_lj_get_username;
250 klass->set_password = jam_account_lj_set_password;
251 klass->get_password = jam_account_lj_get_password;
254 GType
255 jam_account_lj_get_type(void) {
256 static GType new_type = 0;
257 if (!new_type) {
258 const GTypeInfo new_info = {
259 sizeof(JamAccountClass),
260 NULL,
261 NULL,
262 (GClassInitFunc) jam_account_lj_class_init,
263 NULL,
264 NULL,
265 sizeof(JamAccountLJ),
267 NULL
269 new_type = g_type_register_static(JAM_TYPE_ACCOUNT,
270 "JamAccountLJ", &new_info, 0);
272 return new_type;
275 LJServer*
276 jam_host_lj_get_server(JamHostLJ *host) {
277 return host->server;
280 static const char*
281 jam_host_lj_get_stock_icon(void) {
282 return "logjam-server";
285 static GSList*
286 parsemoods(xmlDocPtr doc, xmlNodePtr node) {
287 GSList *moods = NULL;
288 LJMood *mood;
290 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
291 if (xmlStrcmp(node->name, BAD_CAST "mood") == 0) {
292 xmlChar *idstr;
293 char *name;
294 idstr = xmlGetProp(node, BAD_CAST "id");
295 name = jam_xmlGetString(doc, node);
297 /* an older bug causes some bad moods to be stored.
298 * filter them out. */
299 if (idstr == NULL || name == NULL) {
300 if (idstr) xmlFree(idstr);
301 if (name) xmlFree(name);
302 continue;
304 mood = g_new0(LJMood, 1);
305 mood->id = atoi((char*)idstr);
306 xmlFree(idstr);
307 mood->name = name;
308 idstr = xmlGetProp(node, BAD_CAST "parentid");
309 if (idstr) {
310 mood->parentid = atoi((char*)idstr);
311 xmlFree(idstr);
314 moods = g_slist_append(moods, mood);
315 } else XML_GET_END("parsemoods")
317 return moods;
320 static gboolean
321 jam_host_lj_load_xml(JamHost *host, xmlDocPtr doc, xmlNodePtr node) {
322 LJServer *server = JAM_HOST_LJ(host)->server;
324 XML_GET_STR("url", server->url)
325 XML_GET_INT("protocolversion", server->protocolversion)
326 XML_GET_FUNC("moods", server->moods, parsemoods)
327 /* else: */ return FALSE;
329 return TRUE;
332 static void
333 jam_host_lj_save_xml(JamHost *host, xmlNodePtr servernode) {
334 JamHostLJ *hostlj = JAM_HOST_LJ(host);
335 xmlNodePtr node;
336 GSList *l;
337 LJServer *server = hostlj->server;
339 xmlSetProp(servernode, BAD_CAST "protocol", BAD_CAST "livejournal");
341 xmlNewTextChild(servernode, NULL, BAD_CAST "url", BAD_CAST server->url);
343 jam_xmlAddInt(servernode, "protocolversion", server->protocolversion);
345 node = xmlNewChild(servernode, NULL, BAD_CAST "moods", NULL);
346 for (l = server->moods; l != NULL; l = l->next) {
347 LJMood *mood = (LJMood*)l->data;
348 char buf[10];
349 xmlNodePtr moodnode = xmlNewTextChild(node, NULL, BAD_CAST "mood",
350 BAD_CAST mood->name);
352 g_snprintf(buf, 10, "%d", mood->id);
353 xmlSetProp(moodnode, BAD_CAST "id", BAD_CAST buf);
354 if (mood->parentid) {
355 g_snprintf(buf, 10, "%d", mood->parentid);
356 xmlSetProp(moodnode, BAD_CAST "parentid", BAD_CAST buf);
361 static JamAccount*
362 jam_host_lj_make_account(JamHost *host, const char *username) {
363 JamAccount *acc;
364 acc = jam_account_lj_new(JAM_HOST_LJ(host)->server, username);
365 jam_host_add_account(host, acc);
366 return acc;
369 static gboolean
370 jam_host_lj_do_action(JamHost *host, NetContext *ctx, JamDoc *doc, gboolean edit, gboolean delete, GError **err) {
371 LJEditPostEvent *editpostevent;
372 JamAccount *account = jam_doc_get_account(doc);
373 JamAccountLJ *acc = JAM_ACCOUNT_LJ(account);
374 LJEntry *entry;
375 gboolean ret = FALSE;
377 entry = jam_doc_get_entry(doc);
378 if (!edit)
379 entry->itemid = 0;
380 else if (delete) {
381 g_free(entry->event);
382 entry->event = NULL;
385 #if 0
387 if (jam_host_lj_get_server(JAM_HOST_LJ(host))->protocolversion < 1) {
388 /* scan the entry and make sure they're sending ASCII. */
389 unsigned char *p;
390 gboolean invalid = FALSE;
392 for (p = entry->event; *p; p++) {
393 if (*p > 0x7F) {
394 invalid = TRUE;
395 break;
398 if (invalid) {
399 jam_warning(parent, _("Error: Your post contains Unicode "
400 "characters, but you're trying to submit them to a server "
401 "that doesn't support Unicode."));
402 return FALSE;
405 #endif
407 editpostevent = lj_editpostevent_new(jam_account_lj_get_user(acc),
408 jam_doc_get_usejournal(doc), edit, entry);
410 if (net_run_verb_ctx((LJVerb*)editpostevent, ctx, err))
411 ret = TRUE;
413 /*fprintf(stderr, "url: [%s]\n", lj_result_get(((LJVerb *)editpostevent)->result, "url"));*/
414 jam_doc_set_url(doc, lj_result_get(((LJVerb *)editpostevent)->result, "url"));
416 lj_editpostevent_free(editpostevent);
417 lj_entry_free(entry);
419 return ret;
422 static gboolean
423 jam_host_lj_do_post(JamHost *host, NetContext *ctx, void *doc, GError **err) {
424 return jam_host_lj_do_action(host, ctx, doc, FALSE, FALSE, err);
427 static gboolean
428 jam_host_lj_do_edit(JamHost *host, NetContext *ctx, void *doc, GError **err) {
429 return jam_host_lj_do_action(host, ctx, doc, TRUE, FALSE, err);
432 static gboolean
433 jam_host_lj_do_delete(JamHost *host, NetContext *ctx, void *doc, GError **err) {
434 return jam_host_lj_do_action(host, ctx, doc, TRUE, TRUE, err);
437 static void
438 jam_host_lj_class_init(JamHostClass *klass) {
439 klass->get_stock_icon = jam_host_lj_get_stock_icon;
440 klass->save_xml = jam_host_lj_save_xml;
441 klass->load_xml = jam_host_lj_load_xml;
442 klass->make_account = jam_host_lj_make_account;
443 klass->do_post = jam_host_lj_do_post;
444 klass->do_edit = jam_host_lj_do_edit;
445 klass->do_delete = jam_host_lj_do_delete;
448 GType
449 jam_host_lj_get_type(void) {
450 static GType new_type = 0;
451 if (!new_type) {
452 const GTypeInfo new_info = {
453 sizeof(JamHostClass),
454 NULL,
455 NULL,
456 (GClassInitFunc) jam_host_lj_class_init,
457 NULL,
458 NULL,
459 sizeof(JamHostLJ),
461 NULL
463 new_type = g_type_register_static(JAM_TYPE_HOST,
464 "JamHostLJ", &new_info, 0);
466 return new_type;
469 JamHostLJ*
470 jam_host_lj_new(LJServer *s) {
471 JamHostLJ *h = JAM_HOST_LJ(g_object_new(jam_host_lj_get_type(), NULL));
472 h->server = s;
473 return h;