Mercurial > pidgin
comparison libpurple/protocols/myspace/user.c @ 19443:47c9c00878bf
Add msimprpl's user module so we all can compile libpurple again ;)
author | Jeffrey Connelly <jaconnel@calpoly.edu> |
---|---|
date | Mon, 27 Aug 2007 00:00:38 +0000 |
parents | |
children | 44b4e8bd759b 36ba89a2b7da |
comparison
equal
deleted
inserted
replaced
19442:d7cd580c0753 | 19443:47c9c00878bf |
---|---|
1 /* MySpaceIM Protocol Plugin, header file | |
2 * | |
3 * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im> | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License as published by | |
7 * the Free Software Foundation; either version 2 of the License, or | |
8 * (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 * GNU General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 #include "myspace.h" | |
21 | |
22 static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user); | |
23 static gchar *msim_format_now_playing(gchar *band, gchar *song); | |
24 static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, | |
25 gsize len, const gchar *error_message); | |
26 | |
27 /** Format the "now playing" indicator, showing the artist and song. | |
28 * @return Return a new string (must be g_free()'d), or NULL. | |
29 */ | |
30 static gchar * | |
31 msim_format_now_playing(gchar *band, gchar *song) | |
32 { | |
33 if ((band && strlen(band)) || (song && strlen(song))) { | |
34 return g_strdup_printf("%s - %s", | |
35 (band && strlen(band)) ? band : "Unknown Artist", | |
36 (song && strlen(song)) ? song : "Unknown Song"); | |
37 } else { | |
38 return NULL; | |
39 } | |
40 } | |
41 /** Get the MsimUser from a PurpleBuddy, creating it if needed. */ | |
42 MsimUser * | |
43 msim_get_user_from_buddy(PurpleBuddy *buddy) | |
44 { | |
45 MsimUser *user; | |
46 | |
47 if (!buddy) { | |
48 return NULL; | |
49 } | |
50 | |
51 if (!buddy->proto_data) { | |
52 /* No MsimUser for this buddy; make one. */ | |
53 | |
54 /* TODO: where is this freed? */ | |
55 user = g_new0(MsimUser, 1); | |
56 user->buddy = buddy; | |
57 buddy->proto_data = (gpointer)user; | |
58 } | |
59 | |
60 user = (MsimUser *)(buddy->proto_data); | |
61 | |
62 return user; | |
63 } | |
64 | |
65 /** Find and return an MsimUser * representing a user on the buddy list, or NULL. */ | |
66 MsimUser * | |
67 msim_find_user(MsimSession *session, const gchar *username) | |
68 { | |
69 PurpleBuddy *buddy; | |
70 MsimUser *user; | |
71 | |
72 buddy = purple_find_buddy(session->account, username); | |
73 if (!buddy) { | |
74 return NULL; | |
75 } | |
76 | |
77 user = msim_get_user_from_buddy(buddy); | |
78 | |
79 return user; | |
80 } | |
81 | |
82 /** Append user information to a PurpleNotifyUserInfo, given an MsimUser. | |
83 * Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile. | |
84 */ | |
85 void | |
86 msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full) | |
87 { | |
88 gchar *str; | |
89 guint uid; | |
90 guint cv; | |
91 | |
92 /* Useful to identify the account the tooltip refers to. | |
93 * Other prpls show this. */ | |
94 if (user->username) { | |
95 purple_notify_user_info_add_pair(user_info, _("User"), user->username); | |
96 } | |
97 | |
98 uid = purple_blist_node_get_int(&user->buddy->node, "UserID"); | |
99 | |
100 if (full) { | |
101 /* TODO: link to username, if available */ | |
102 purple_notify_user_info_add_pair(user_info, _("Profile"), | |
103 g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>", | |
104 uid, uid)); | |
105 } | |
106 | |
107 | |
108 /* a/s/l...the vitals */ | |
109 if (user->age) { | |
110 purple_notify_user_info_add_pair(user_info, _("Age"), | |
111 g_strdup_printf("%d", user->age)); | |
112 } | |
113 | |
114 if (user->gender && strlen(user->gender)) { | |
115 purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender); | |
116 } | |
117 | |
118 if (user->location && strlen(user->location)) { | |
119 purple_notify_user_info_add_pair(user_info, _("Location"), user->location); | |
120 } | |
121 | |
122 /* Other information */ | |
123 if (user->headline && strlen(user->headline)) { | |
124 purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline); | |
125 } | |
126 | |
127 str = msim_format_now_playing(user->band_name, user->song_name); | |
128 if (str && strlen(str)) { | |
129 purple_notify_user_info_add_pair(user_info, _("Song"), str); | |
130 } | |
131 | |
132 /* Note: total friends only available if looked up by uid, not username. */ | |
133 if (user->total_friends) { | |
134 purple_notify_user_info_add_pair(user_info, _("Total Friends"), | |
135 g_strdup_printf("%d", user->total_friends)); | |
136 } | |
137 | |
138 if (full) { | |
139 /* Client information */ | |
140 | |
141 str = user->client_info; | |
142 cv = user->client_cv; | |
143 | |
144 if (str && cv != 0) { | |
145 purple_notify_user_info_add_pair(user_info, _("Client Version"), | |
146 g_strdup_printf("%s (build %d)", str, cv)); | |
147 } else if (str) { | |
148 purple_notify_user_info_add_pair(user_info, _("Client Version"), | |
149 g_strdup(str)); | |
150 } else if (cv) { | |
151 purple_notify_user_info_add_pair(user_info, _("Client Version"), | |
152 g_strdup_printf("Build %d", cv)); | |
153 } | |
154 } | |
155 } | |
156 | |
157 /** Store a field of information about a buddy. */ | |
158 void | |
159 msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user) | |
160 { | |
161 if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) { | |
162 /* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */ | |
163 if (user->buddy) | |
164 { | |
165 purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name); | |
166 purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str)); | |
167 } | |
168 /* Need to store in MsimUser, too? What if not on blist? */ | |
169 } else if (g_str_equal(key_str, "Age")) { | |
170 user->age = atol(value_str); | |
171 } else if (g_str_equal(key_str, "Gender")) { | |
172 user->gender = g_strdup(value_str); | |
173 } else if (g_str_equal(key_str, "Location")) { | |
174 user->location = g_strdup(value_str); | |
175 } else if (g_str_equal(key_str, "TotalFriends")) { | |
176 user->total_friends = atol(value_str); | |
177 } else if (g_str_equal(key_str, "DisplayName")) { | |
178 user->display_name = g_strdup(value_str); | |
179 } else if (g_str_equal(key_str, "BandName")) { | |
180 user->band_name = g_strdup(value_str); | |
181 } else if (g_str_equal(key_str, "SongName")) { | |
182 user->song_name = g_strdup(value_str); | |
183 } else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) { | |
184 /* Ignore because PurpleBuddy knows this already */ | |
185 ; | |
186 } else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) { | |
187 const gchar *previous_url; | |
188 | |
189 user->image_url = g_strdup(value_str); | |
190 | |
191 /* Instead of showing 'no photo' picture, show nothing. */ | |
192 if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif")) | |
193 { | |
194 purple_buddy_icons_set_for_user(user->buddy->account, | |
195 user->buddy->name, | |
196 NULL, 0, NULL); | |
197 return; | |
198 } | |
199 | |
200 /* TODO: use ETag for checksum */ | |
201 previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy); | |
202 | |
203 /* Only download if URL changed */ | |
204 if (!previous_url || !g_str_equal(previous_url, user->image_url)) { | |
205 purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user); | |
206 } | |
207 } else if (g_str_equal(key_str, "LastImageUpdated")) { | |
208 /* TODO: use somewhere */ | |
209 user->last_image_updated = atol(value_str); | |
210 } else if (g_str_equal(key_str, "Headline")) { | |
211 user->headline = g_strdup(value_str); | |
212 } else { | |
213 /* TODO: other fields in MsimUser */ | |
214 gchar *msg; | |
215 | |
216 msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s", | |
217 key_str, value_str); | |
218 | |
219 msim_unrecognized(NULL, NULL, msg); | |
220 | |
221 g_free(msg); | |
222 } | |
223 } | |
224 | |
225 /** Save buddy information to the buddy list from a user info reply message. | |
226 * | |
227 * @param session | |
228 * @param msg The user information reply, with any amount of information. | |
229 * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data. | |
230 * | |
231 * Variable information is saved to the passed MsimUser structure. Permanent | |
232 * information (UserID) is stored in the blist node of the buddy list (and | |
233 * ends up in blist.xml, persisted to disk) if it exists. | |
234 * | |
235 * If the function has no buddy information, this function | |
236 * is a no-op (and returns FALSE). | |
237 * | |
238 */ | |
239 gboolean | |
240 msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user) | |
241 { | |
242 gchar *username; | |
243 MsimMessage *body, *body_node; | |
244 | |
245 g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); | |
246 g_return_val_if_fail(msg != NULL, FALSE); | |
247 | |
248 body = msim_msg_get_dictionary(msg, "body"); | |
249 if (!body) { | |
250 return FALSE; | |
251 } | |
252 | |
253 username = msim_msg_get_string(body, "UserName"); | |
254 | |
255 if (!username) { | |
256 purple_debug_info("msim", | |
257 "msim_process_reply: not caching body, no UserName\n"); | |
258 msim_msg_free(body); | |
259 g_free(username); | |
260 return FALSE; | |
261 } | |
262 | |
263 /* Null user = find and store in PurpleBuddy's proto_data */ | |
264 if (!user) { | |
265 user = msim_find_user(session, username); | |
266 if (!user) { | |
267 msim_msg_free(body); | |
268 g_free(username); | |
269 return FALSE; | |
270 } | |
271 } | |
272 | |
273 /* TODO: make looping over MsimMessage's easier. */ | |
274 for (body_node = body; | |
275 body_node != NULL; | |
276 body_node = msim_msg_get_next_element_node(body_node)) | |
277 { | |
278 const gchar *key_str; | |
279 gchar *value_str; | |
280 MsimMessageElement *elem; | |
281 | |
282 elem = (MsimMessageElement *)body_node->data; | |
283 key_str = elem->name; | |
284 | |
285 value_str = msim_msg_get_string_from_element(elem); | |
286 msim_store_user_info_each(key_str, value_str, user); | |
287 g_free(value_str); | |
288 } | |
289 | |
290 if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN && | |
291 msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) { | |
292 /* TODO: do something with our own IM info, if we need it for some | |
293 * specific purpose. Otherwise it is available on the buddy list, | |
294 * if the user has themselves as their own buddy. | |
295 * | |
296 * However, much of the info is already available in MsimSession, | |
297 * stored in msim_we_are_logged_on(). */ | |
298 } else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN && | |
299 msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) { | |
300 /* TODO: same as above, but for MySpace info. */ | |
301 } | |
302 | |
303 msim_msg_free(body); | |
304 | |
305 return TRUE; | |
306 } | |
307 | |
308 /** | |
309 * Asynchronously lookup user information, calling callback when receive result. | |
310 * | |
311 * @param session | |
312 * @param user The user id, email address, or username. Not freed. | |
313 * @param cb Callback, called with user information when available. | |
314 * @param data An arbitray data pointer passed to the callback. | |
315 */ | |
316 /* TODO: change to not use callbacks */ | |
317 void | |
318 msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data) | |
319 { | |
320 MsimMessage *body; | |
321 gchar *field_name; | |
322 guint rid, cmd, dsn, lid; | |
323 | |
324 g_return_if_fail(MSIM_SESSION_VALID(session)); | |
325 g_return_if_fail(user != NULL); | |
326 /* Callback can be null to not call anything, just lookup & store information. */ | |
327 /*g_return_if_fail(cb != NULL);*/ | |
328 | |
329 purple_debug_info("msim", "msim_lookup_userid: " | |
330 "asynchronously looking up <%s>\n", user); | |
331 | |
332 msim_msg_dump("msim_lookup_user: data=%s\n", (MsimMessage *)data); | |
333 | |
334 /* Setup callback. Response will be associated with request using 'rid'. */ | |
335 rid = msim_new_reply_callback(session, cb, data); | |
336 | |
337 /* Send request */ | |
338 | |
339 cmd = MSIM_CMD_GET; | |
340 | |
341 if (msim_is_userid(user)) { | |
342 field_name = "UserID"; | |
343 dsn = MG_MYSPACE_INFO_BY_ID_DSN; | |
344 lid = MG_MYSPACE_INFO_BY_ID_LID; | |
345 } else if (msim_is_email(user)) { | |
346 field_name = "Email"; | |
347 dsn = MG_MYSPACE_INFO_BY_STRING_DSN; | |
348 lid = MG_MYSPACE_INFO_BY_STRING_LID; | |
349 } else { | |
350 field_name = "UserName"; | |
351 dsn = MG_MYSPACE_INFO_BY_STRING_DSN; | |
352 lid = MG_MYSPACE_INFO_BY_STRING_LID; | |
353 } | |
354 | |
355 body = msim_msg_new( | |
356 field_name, MSIM_TYPE_STRING, g_strdup(user), | |
357 NULL); | |
358 | |
359 g_return_if_fail(msim_send(session, | |
360 "persist", MSIM_TYPE_INTEGER, 1, | |
361 "sesskey", MSIM_TYPE_INTEGER, session->sesskey, | |
362 "cmd", MSIM_TYPE_INTEGER, 1, | |
363 "dsn", MSIM_TYPE_INTEGER, dsn, | |
364 "uid", MSIM_TYPE_INTEGER, session->userid, | |
365 "lid", MSIM_TYPE_INTEGER, lid, | |
366 "rid", MSIM_TYPE_INTEGER, rid, | |
367 "body", MSIM_TYPE_DICTIONARY, body, | |
368 NULL)); | |
369 } | |
370 | |
371 | |
372 /** | |
373 * Check if a string is a userid (all numeric). | |
374 * | |
375 * @param user The user id, email, or name. | |
376 * | |
377 * @return TRUE if is userid, FALSE if not. | |
378 */ | |
379 gboolean | |
380 msim_is_userid(const gchar *user) | |
381 { | |
382 g_return_val_if_fail(user != NULL, FALSE); | |
383 | |
384 return strspn(user, "0123456789") == strlen(user); | |
385 } | |
386 | |
387 /** | |
388 * Check if a string is an email address (contains an @). | |
389 * | |
390 * @param user The user id, email, or name. | |
391 * | |
392 * @return TRUE if is an email, FALSE if not. | |
393 * | |
394 * This function is not intended to be used as a generic | |
395 * means of validating email addresses, but to distinguish | |
396 * between a user represented by an email address from | |
397 * other forms of identification. | |
398 */ | |
399 gboolean | |
400 msim_is_email(const gchar *user) | |
401 { | |
402 g_return_val_if_fail(user != NULL, FALSE); | |
403 | |
404 return strchr(user, '@') != NULL; | |
405 } | |
406 | |
407 | |
408 /** Callback for when a buddy icon finished being downloaded. */ | |
409 static void | |
410 msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, | |
411 gpointer user_data, | |
412 const gchar *url_text, | |
413 gsize len, | |
414 const gchar *error_message) | |
415 { | |
416 MsimUser *user; | |
417 | |
418 user = (MsimUser *)user_data; | |
419 | |
420 purple_debug_info("msim_downloaded_buddy_icon", | |
421 "Downloaded %d bytes\n", len); | |
422 | |
423 if (!url_text) { | |
424 purple_debug_info("msim_downloaded_buddy_icon", | |
425 "failed to download icon for %s", | |
426 user->buddy->name); | |
427 return; | |
428 } | |
429 | |
430 purple_buddy_icons_set_for_user(user->buddy->account, | |
431 user->buddy->name, | |
432 g_memdup((gchar *)url_text, len), len, | |
433 /* Use URL itself as buddy icon "checksum" (TODO: ETag) */ | |
434 user->image_url); /* checksum */ | |
435 } | |
436 | |
437 |