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