Mercurial > pidgin
annotate src/protocols/jabber/buddy.c @ 12919:248b8b39c671
[gaim-migrate @ 15272]
Replace GaimBlistNodeAction with the more generic GaimMenuAction, this is in
preparation for letting the chat room user list have extensible menus like the
blist entries do. (I know it's not exactly the prettiest, and the callback
isn't exactly type-safe, when we eventually gobjectify everything we can get
some safety back by using (GObject, gpointer) but that's for later.)
I'm planning to look into merging GaimPluginActions into GaimMenuActions as
well.
committer: Tailor Script <tailor@pidgin.im>
author | Etan Reisner <pidgin@unreliablesource.net> |
---|---|
date | Tue, 17 Jan 2006 23:22:19 +0000 |
parents | 41cf9be29754 |
children | 75ac13ab161f |
rev | line source |
---|---|
7014 | 1 /* |
2 * gaim - Jabber Protocol Plugin | |
3 * | |
4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 */ | |
21 #include "internal.h" | |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10662
diff
changeset
|
22 #include "cipher.h" |
7014 | 23 #include "debug.h" |
7076 | 24 #include "imgstore.h" |
9713 | 25 #include "prpl.h" |
7014 | 26 #include "notify.h" |
27 #include "request.h" | |
28 #include "util.h" | |
7395 | 29 #include "xmlnode.h" |
7014 | 30 |
31 #include "buddy.h" | |
32 #include "chat.h" | |
33 #include "jabber.h" | |
34 #include "iq.h" | |
35 #include "presence.h" | |
11675 | 36 #include "xdata.h" |
7014 | 37 |
7116 | 38 void jabber_buddy_free(JabberBuddy *jb) |
39 { | |
40 g_return_if_fail(jb != NULL); | |
41 | |
42 if(jb->error_msg) | |
43 g_free(jb->error_msg); | |
44 while(jb->resources) | |
45 jabber_buddy_resource_free(jb->resources->data); | |
46 | |
47 g_free(jb); | |
48 } | |
49 | |
7014 | 50 JabberBuddy *jabber_buddy_find(JabberStream *js, const char *name, |
51 gboolean create) | |
52 { | |
53 JabberBuddy *jb; | |
7445 | 54 const char *realname; |
7014 | 55 |
7445 | 56 if(!(realname = jabber_normalize(js->gc->account, name))) |
7014 | 57 return NULL; |
58 | |
59 jb = g_hash_table_lookup(js->buddies, realname); | |
60 | |
61 if(!jb && create) { | |
62 jb = g_new0(JabberBuddy, 1); | |
63 g_hash_table_insert(js->buddies, g_strdup(realname), jb); | |
64 } | |
65 | |
66 return jb; | |
67 } | |
68 | |
69 | |
70 JabberBuddyResource *jabber_buddy_find_resource(JabberBuddy *jb, | |
71 const char *resource) | |
72 { | |
73 JabberBuddyResource *jbr = NULL; | |
74 GList *l; | |
75 | |
76 if(!jb) | |
77 return NULL; | |
78 | |
79 for(l = jb->resources; l; l = l->next) | |
80 { | |
81 if(!jbr && !resource) { | |
82 jbr = l->data; | |
83 } else if(!resource) { | |
84 if(((JabberBuddyResource *)l->data)->priority >= jbr->priority) | |
85 jbr = l->data; | |
86 } else if(((JabberBuddyResource *)l->data)->name) { | |
87 if(!strcmp(((JabberBuddyResource *)l->data)->name, resource)) { | |
88 jbr = l->data; | |
89 break; | |
90 } | |
91 } | |
92 } | |
93 | |
94 return jbr; | |
95 } | |
96 | |
9954 | 97 JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource, |
98 int priority, JabberBuddyState state, const char *status) | |
7014 | 99 { |
100 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource); | |
101 | |
102 if(!jbr) { | |
103 jbr = g_new0(JabberBuddyResource, 1); | |
7116 | 104 jbr->jb = jb; |
7014 | 105 jbr->name = g_strdup(resource); |
106 jbr->capabilities = JABBER_CAP_XHTML; | |
107 jb->resources = g_list_append(jb->resources, jbr); | |
108 } | |
109 jbr->priority = priority; | |
110 jbr->state = state; | |
111 if(jbr->status) | |
112 g_free(jbr->status); | |
113 jbr->status = g_strdup(status); | |
9954 | 114 |
115 return jbr; | |
7014 | 116 } |
117 | |
7116 | 118 void jabber_buddy_resource_free(JabberBuddyResource *jbr) |
119 { | |
120 g_return_if_fail(jbr != NULL); | |
121 | |
122 jbr->jb->resources = g_list_remove(jbr->jb->resources, jbr); | |
123 | |
124 g_free(jbr->name); | |
125 if(jbr->status) | |
126 g_free(jbr->status); | |
8400 | 127 if(jbr->thread_id) |
128 g_free(jbr->thread_id); | |
7116 | 129 g_free(jbr); |
130 } | |
131 | |
7014 | 132 void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource) |
133 { | |
134 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource); | |
135 | |
136 if(!jbr) | |
137 return; | |
138 | |
7116 | 139 jabber_buddy_resource_free(jbr); |
7014 | 140 } |
141 | |
142 const char *jabber_buddy_get_status_msg(JabberBuddy *jb) | |
143 { | |
144 JabberBuddyResource *jbr; | |
145 | |
146 if(!jb) | |
147 return NULL; | |
148 | |
149 jbr = jabber_buddy_find_resource(jb, NULL); | |
150 | |
151 if(!jbr) | |
152 return NULL; | |
153 | |
154 return jbr->status; | |
155 } | |
156 | |
157 /******* | |
158 * This is the old vCard stuff taken from the old prpl. vCards, by definition | |
159 * are a temporary thing until jabber can get its act together and come up | |
160 * with a format for user information, hence the namespace of 'vcard-temp' | |
161 * | |
162 * Since I don't feel like putting that much work into something that's | |
163 * _supposed_ to go away, i'm going to just copy the kludgy old code here, | |
164 * and make it purdy when jabber comes up with a standards-track JEP to | |
165 * replace vcard-temp | |
166 * --Nathan | |
167 *******/ | |
168 | |
169 /*---------------------------------------*/ | |
170 /* Jabber "set info" (vCard) support */ | |
171 /*---------------------------------------*/ | |
172 | |
173 /* | |
174 * V-Card format: | |
175 * | |
176 * <vCard prodid='' version='' xmlns=''> | |
177 * <FN></FN> | |
178 * <N> | |
179 * <FAMILY/> | |
180 * <GIVEN/> | |
181 * </N> | |
182 * <NICKNAME/> | |
183 * <URL/> | |
184 * <ADR> | |
185 * <STREET/> | |
186 * <EXTADD/> | |
187 * <LOCALITY/> | |
188 * <REGION/> | |
189 * <PCODE/> | |
190 * <COUNTRY/> | |
191 * </ADR> | |
192 * <TEL/> | |
193 * <EMAIL/> | |
194 * <ORG> | |
195 * <ORGNAME/> | |
196 * <ORGUNIT/> | |
197 * </ORG> | |
198 * <TITLE/> | |
199 * <ROLE/> | |
200 * <DESC/> | |
201 * <BDAY/> | |
202 * </vCard> | |
203 * | |
204 * See also: | |
205 * | |
206 * http://docs.jabber.org/proto/html/vcard-temp.html | |
207 * http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd | |
208 */ | |
209 | |
210 /* | |
211 * Cross-reference user-friendly V-Card entry labels to vCard XML tags | |
212 * and attributes. | |
213 * | |
214 * Order is (or should be) unimportant. For example: we have no way of | |
215 * knowing in what order real data will arrive. | |
216 * | |
217 * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag | |
218 * name, XML tag's parent tag "path" (relative to vCard node). | |
219 * | |
220 * List is terminated by a NULL label pointer. | |
221 * | |
222 * Entries with no label text, but with XML tag and parent tag | |
223 * entries, are used by V-Card XML construction routines to | |
224 * "automagically" construct the appropriate XML node tree. | |
225 * | |
226 * Thoughts on future direction/expansion | |
227 * | |
228 * This is a "simple" vCard. | |
229 * | |
230 * It is possible for nodes other than the "vCard" node to have | |
231 * attributes. Should that prove necessary/desirable, add an | |
232 * "attributes" pointer to the vcard_template struct, create the | |
233 * necessary tag_attr structs, and add 'em to the vcard_dflt_data | |
234 * array. | |
235 * | |
236 * The above changes will (obviously) require changes to the vCard | |
237 * construction routines. | |
238 */ | |
239 | |
240 struct vcard_template { | |
241 char *label; /* label text pointer */ | |
242 char *text; /* entry text pointer */ | |
243 int visible; /* should entry field be "visible?" */ | |
244 int editable; /* should entry field be editable? */ | |
245 char *tag; /* tag text */ | |
246 char *ptag; /* parent tag "path" text */ | |
247 char *url; /* vCard display format if URL */ | |
248 } vcard_template_data[] = { | |
249 {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, | |
250 {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, | |
251 {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, | |
252 {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, | |
253 {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "<A HREF=\"%s\">%s</A>"}, | |
254 {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, | |
255 {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, | |
256 {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, | |
257 {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, | |
258 {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, | |
259 {N_("Country"), NULL, TRUE, TRUE, "COUNTRY", "ADR", NULL}, | |
11361 | 260 {N_("Telephone"), NULL, TRUE, TRUE, "NUMBER", "TEL", NULL}, |
261 {N_("Email"), NULL, TRUE, TRUE, "USERID", "EMAIL", "<A HREF=\"mailto:%s\">%s</A>"}, | |
7014 | 262 {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, |
263 {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, | |
264 {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, | |
265 {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, | |
266 {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, | |
267 {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, | |
268 {"", NULL, TRUE, TRUE, "N", NULL, NULL}, | |
269 {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, | |
270 {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, | |
271 {NULL, NULL, 0, 0, NULL, NULL, NULL} | |
272 }; | |
273 | |
274 /* | |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8401
diff
changeset
|
275 * The "vCard" tag's attribute list... |
7014 | 276 */ |
277 struct tag_attr { | |
278 char *attr; | |
279 char *value; | |
280 } vcard_tag_attr_list[] = { | |
281 {"prodid", "-//HandGen//NONSGML vGen v1.0//EN"}, | |
282 {"version", "2.0", }, | |
283 {"xmlns", "vcard-temp", }, | |
284 {NULL, NULL}, | |
285 }; | |
286 | |
287 | |
288 /* | |
289 * Insert a tag node into an xmlnode tree, recursively inserting parent tag | |
290 * nodes as necessary | |
291 * | |
292 * Returns pointer to inserted node | |
293 * | |
294 * Note to hackers: this code is designed to be re-entrant (it's recursive--it | |
295 * calls itself), so don't put any "static"s in here! | |
296 */ | |
297 static xmlnode *insert_tag_to_parent_tag(xmlnode *start, const char *parent_tag, const char *new_tag) | |
298 { | |
299 xmlnode *x = NULL; | |
300 | |
301 /* | |
302 * If the parent tag wasn't specified, see if we can get it | |
303 * from the vCard template struct. | |
304 */ | |
305 if(parent_tag == NULL) { | |
306 struct vcard_template *vc_tp = vcard_template_data; | |
307 | |
308 while(vc_tp->label != NULL) { | |
309 if(strcmp(vc_tp->tag, new_tag) == 0) { | |
310 parent_tag = vc_tp->ptag; | |
311 break; | |
312 } | |
313 ++vc_tp; | |
314 } | |
315 } | |
316 | |
317 /* | |
318 * If we have a parent tag... | |
319 */ | |
320 if(parent_tag != NULL ) { | |
321 /* | |
322 * Try to get the parent node for a tag | |
323 */ | |
324 if((x = xmlnode_get_child(start, parent_tag)) == NULL) { | |
325 /* | |
326 * Descend? | |
327 */ | |
328 char *grand_parent = g_strdup(parent_tag); | |
329 char *parent; | |
330 | |
331 if((parent = strrchr(grand_parent, '/')) != NULL) { | |
332 *(parent++) = '\0'; | |
333 x = insert_tag_to_parent_tag(start, grand_parent, parent); | |
334 } else { | |
335 x = xmlnode_new_child(start, grand_parent); | |
336 } | |
337 g_free(grand_parent); | |
338 } else { | |
339 /* | |
340 * We found *something* to be the parent node. | |
341 * Note: may be the "root" node! | |
342 */ | |
343 xmlnode *y; | |
344 if((y = xmlnode_get_child(x, new_tag)) != NULL) { | |
345 return(y); | |
346 } | |
347 } | |
348 } | |
349 | |
350 /* | |
351 * insert the new tag into its parent node | |
352 */ | |
353 return(xmlnode_new_child((x == NULL? start : x), new_tag)); | |
354 } | |
355 | |
356 /* | |
357 * Send vCard info to Jabber server | |
358 */ | |
359 void jabber_set_info(GaimConnection *gc, const char *info) | |
360 { | |
361 JabberIq *iq; | |
362 JabberStream *js = gc->proto_data; | |
363 xmlnode *vc_node; | |
11303
10066662176a
[gaim-migrate @ 13503]
Richard Laager <rlaager@wiktel.com>
parents:
11183
diff
changeset
|
364 char *avatar_file = NULL; |
7014 | 365 |
10189 | 366 if(js->avatar_hash) |
367 g_free(js->avatar_hash); | |
368 js->avatar_hash = NULL; | |
7014 | 369 |
370 /* | |
371 * Send only if there's actually any *information* to send | |
372 */ | |
11388 | 373 vc_node = info ? xmlnode_from_str(info, -1) : NULL; |
11318 | 374 avatar_file = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(gc->account)); |
10189 | 375 |
376 if(!vc_node && avatar_file) { | |
377 vc_node = xmlnode_new("vCard"); | |
378 } | |
7014 | 379 |
380 if(vc_node) { | |
381 if (vc_node->name && | |
10189 | 382 !g_ascii_strncasecmp(vc_node->name, "vCard", 5)) { |
383 GError *error = NULL; | |
11509 | 384 gchar *avatar_data_tmp; |
385 guchar *avatar_data; | |
10189 | 386 gsize avatar_len; |
387 | |
11509 | 388 if(avatar_file && g_file_get_contents(avatar_file, &avatar_data_tmp, &avatar_len, &error)) { |
10941 | 389 xmlnode *photo, *binval; |
11127 | 390 gchar *enc; |
10189 | 391 int i; |
392 unsigned char hashval[20]; | |
393 char *p, hash[41]; | |
394 | |
11521 | 395 avatar_data = (guchar *) avatar_data_tmp; |
10189 | 396 photo = xmlnode_new_child(vc_node, "PHOTO"); |
10941 | 397 binval = xmlnode_new_child(photo, "BINVAL"); |
10189 | 398 enc = gaim_base64_encode(avatar_data, avatar_len); |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10662
diff
changeset
|
399 |
11183 | 400 gaim_cipher_digest_region("sha1", (guchar *)avatar_data, |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
401 avatar_len, sizeof(hashval), |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
402 hashval, NULL); |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10662
diff
changeset
|
403 |
10189 | 404 p = hash; |
405 for(i=0; i<20; i++, p+=2) | |
406 snprintf(p, 3, "%02x", hashval[i]); | |
407 js->avatar_hash = g_strdup(hash); | |
408 | |
10941 | 409 xmlnode_insert_data(binval, enc, -1); |
10189 | 410 g_free(enc); |
411 g_free(avatar_data); | |
10504 | 412 } else if (error != NULL) { |
10189 | 413 g_error_free(error); |
414 } | |
11303
10066662176a
[gaim-migrate @ 13503]
Richard Laager <rlaager@wiktel.com>
parents:
11183
diff
changeset
|
415 g_free(avatar_file); |
10189 | 416 |
7014 | 417 iq = jabber_iq_new(js, JABBER_IQ_SET); |
418 xmlnode_insert_child(iq->node, vc_node); | |
419 jabber_iq_send(iq); | |
420 } else { | |
421 xmlnode_free(vc_node); | |
422 } | |
423 } | |
424 } | |
425 | |
10189 | 426 void jabber_set_buddy_icon(GaimConnection *gc, const char *iconfile) |
427 { | |
428 GaimPresence *gpresence; | |
429 GaimStatus *status; | |
430 | |
431 jabber_set_info(gc, gaim_account_get_user_info(gc->account)); | |
432 | |
433 gpresence = gaim_account_get_presence(gc->account); | |
434 status = gaim_presence_get_active_status(gpresence); | |
10216 | 435 jabber_presence_send(gc->account, status); |
10189 | 436 } |
437 | |
7014 | 438 /* |
439 * This is the callback from the "ok clicked" for "set vCard" | |
440 * | |
441 * Formats GSList data into XML-encoded string and returns a pointer | |
442 * to said string. | |
443 * | |
444 * g_free()'ing the returned string space is the responsibility of | |
445 * the caller. | |
446 */ | |
447 static void | |
448 jabber_format_info(GaimConnection *gc, GaimRequestFields *fields) | |
449 { | |
450 GaimAccount *account; | |
451 xmlnode *vc_node; | |
452 GaimRequestField *field; | |
453 const char *text; | |
454 char *p; | |
455 const struct vcard_template *vc_tp; | |
456 struct tag_attr *tag_attr; | |
457 | |
458 vc_node = xmlnode_new("vCard"); | |
459 | |
460 for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) | |
461 xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value); | |
462 | |
463 for (vc_tp = vcard_template_data; vc_tp->label != NULL; vc_tp++) { | |
464 if (*vc_tp->label == '\0') | |
465 continue; | |
466 | |
467 field = gaim_request_fields_get_field(fields, vc_tp->tag); | |
468 text = gaim_request_field_string_get_value(field); | |
469 | |
470 | |
471 if (text != NULL && *text != '\0') { | |
472 xmlnode *xp; | |
473 | |
9339 | 474 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
475 "Setting %s to '%s'\n", vc_tp->tag, text); | |
476 | |
7014 | 477 if ((xp = insert_tag_to_parent_tag(vc_node, |
478 NULL, vc_tp->tag)) != NULL) { | |
479 | |
480 xmlnode_insert_data(xp, text, -1); | |
481 } | |
482 } | |
483 } | |
484 | |
7642 | 485 p = xmlnode_to_str(vc_node, NULL); |
7014 | 486 xmlnode_free(vc_node); |
487 | |
488 account = gaim_connection_get_account(gc); | |
489 | |
490 if (account != NULL) { | |
491 gaim_account_set_user_info(account, p); | |
492 | |
493 if (gc != NULL) | |
494 serv_set_info(gc, p); | |
495 } | |
496 | |
497 g_free(p); | |
498 } | |
499 | |
500 /* | |
501 * This gets executed by the proto action | |
502 * | |
503 * Creates a new GaimRequestFields struct, gets the XML-formatted user_info | |
504 * string (if any) into GSLists for the (multi-entry) edit dialog and | |
505 * calls the set_vcard dialog. | |
506 */ | |
9015 | 507 void jabber_setup_set_info(GaimPluginAction *action) |
7014 | 508 { |
9015 | 509 GaimConnection *gc = (GaimConnection *) action->context; |
7014 | 510 GaimRequestFields *fields; |
511 GaimRequestFieldGroup *group; | |
512 GaimRequestField *field; | |
513 const struct vcard_template *vc_tp; | |
514 char *user_info; | |
515 char *cdata; | |
516 xmlnode *x_vc_data = NULL; | |
517 | |
518 fields = gaim_request_fields_new(); | |
519 group = gaim_request_field_group_new(NULL); | |
520 gaim_request_fields_add_group(fields, group); | |
521 | |
522 /* | |
523 * Get existing, XML-formatted, user info | |
524 */ | |
525 if((user_info = g_strdup(gaim_account_get_user_info(gc->account))) != NULL) | |
526 x_vc_data = xmlnode_from_str(user_info, -1); | |
527 else | |
528 user_info = g_strdup(""); | |
529 | |
530 /* | |
531 * Set up GSLists for edit with labels from "template," data from user info | |
532 */ | |
533 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
534 xmlnode *data_node; | |
535 if((vc_tp->label)[0] == '\0') | |
536 continue; | |
537 if(vc_tp->ptag == NULL) { | |
538 data_node = xmlnode_get_child(x_vc_data, vc_tp->tag); | |
539 } else { | |
540 gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag); | |
541 data_node = xmlnode_get_child(x_vc_data, tag); | |
542 g_free(tag); | |
543 } | |
544 if(data_node) | |
545 cdata = xmlnode_get_data(data_node); | |
546 else | |
547 cdata = NULL; | |
548 | |
549 if(strcmp(vc_tp->tag, "DESC") == 0) { | |
550 field = gaim_request_field_string_new(vc_tp->tag, | |
551 _(vc_tp->label), cdata, | |
552 TRUE); | |
553 } else { | |
554 field = gaim_request_field_string_new(vc_tp->tag, | |
555 _(vc_tp->label), cdata, | |
556 FALSE); | |
557 } | |
558 | |
559 gaim_request_field_group_add_field(group, field); | |
560 } | |
561 | |
562 if(x_vc_data != NULL) | |
563 xmlnode_free(x_vc_data); | |
564 | |
565 g_free(user_info); | |
566 | |
567 gaim_request_fields(gc, _("Edit Jabber vCard"), | |
568 _("Edit Jabber vCard"), | |
569 _("All items below are optional. Enter only the " | |
570 "information with which you feel comfortable."), | |
571 fields, | |
572 _("Save"), G_CALLBACK(jabber_format_info), | |
573 _("Cancel"), NULL, | |
574 gc); | |
575 } | |
576 | |
577 /*---------------------------------------*/ | |
578 /* End Jabber "set info" (vCard) support */ | |
579 /*---------------------------------------*/ | |
580 | |
581 /****** | |
582 * end of that ancient crap that needs to die | |
583 ******/ | |
584 | |
585 | |
7395 | 586 static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data) |
7014 | 587 { |
588 GList *resources; | |
589 const char *from = xmlnode_get_attrib(packet, "from"); | |
590 JabberBuddy *jb; | |
591 JabberBuddyResource *jbr; | |
592 GString *info_text; | |
7306 | 593 char *resource_name; |
7955 | 594 char *bare_jid; |
8213 | 595 char *text; |
7014 | 596 xmlnode *vcard; |
7955 | 597 GaimBuddy *b; |
10189 | 598 GSList *imgids = NULL; |
7014 | 599 |
600 if(!from) | |
601 return; | |
602 | |
11361 | 603 if(!(jb = jabber_buddy_find(js, from, TRUE))) |
604 return; | |
605 | |
10490 | 606 /* XXX: handle the error case */ |
607 | |
7014 | 608 resource_name = jabber_get_resource(from); |
7955 | 609 bare_jid = jabber_get_bare_jid(from); |
610 | |
611 b = gaim_find_buddy(js->gc->account, bare_jid); | |
7014 | 612 |
11361 | 613 |
7014 | 614 info_text = g_string_new(""); |
615 | |
616 if(resource_name) { | |
617 jbr = jabber_buddy_find_resource(jb, resource_name); | |
618 if(jbr) { | |
7145 | 619 char *purdy = NULL; |
620 if(jbr->status) | |
621 purdy = gaim_strdup_withhtml(jbr->status); | |
8213 | 622 g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/>", |
9954 | 623 _("Status"), jabber_buddy_state_get_name(jbr->state), |
7014 | 624 purdy ? ": " : "", |
625 purdy ? purdy : ""); | |
7145 | 626 if(purdy) |
627 g_free(purdy); | |
7014 | 628 } else { |
8213 | 629 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 630 _("Status"), _("Unknown")); |
631 } | |
632 } else { | |
633 for(resources = jb->resources; resources; resources = resources->next) { | |
7145 | 634 char *purdy = NULL; |
7014 | 635 jbr = resources->data; |
7145 | 636 if(jbr->status) |
637 purdy = gaim_strdup_withhtml(jbr->status); | |
8213 | 638 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 639 _("Resource"), jbr->name); |
8213 | 640 g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/><br/>", |
9954 | 641 _("Status"), jabber_buddy_state_get_name(jbr->state), |
7014 | 642 purdy ? ": " : "", |
643 purdy ? purdy : ""); | |
7145 | 644 if(purdy) |
645 g_free(purdy); | |
7014 | 646 } |
647 } | |
648 | |
7306 | 649 g_free(resource_name); |
650 | |
10189 | 651 if((vcard = xmlnode_get_child(packet, "vCard")) || |
652 (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) { | |
7014 | 653 xmlnode *child; |
654 for(child = vcard->child; child; child = child->next) | |
655 { | |
656 xmlnode *child2; | |
657 | |
8135 | 658 if(child->type != XMLNODE_TYPE_TAG) |
7014 | 659 continue; |
660 | |
661 text = xmlnode_get_data(child); | |
662 if(text && !strcmp(child->name, "FN")) { | |
8213 | 663 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 664 _("Full Name"), text); |
665 } else if(!strcmp(child->name, "N")) { | |
666 for(child2 = child->child; child2; child2 = child2->next) | |
667 { | |
668 char *text2; | |
669 | |
8135 | 670 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 671 continue; |
672 | |
673 text2 = xmlnode_get_data(child2); | |
674 if(text2 && !strcmp(child2->name, "FAMILY")) { | |
675 g_string_append_printf(info_text, | |
8213 | 676 "<b>%s:</b> %s<br/>", |
7014 | 677 _("Family Name"), text2); |
678 } else if(text2 && !strcmp(child2->name, "GIVEN")) { | |
679 g_string_append_printf(info_text, | |
8213 | 680 "<b>%s:</b> %s<br/>", |
7014 | 681 _("Given Name"), text2); |
682 } else if(text2 && !strcmp(child2->name, "MIDDLE")) { | |
683 g_string_append_printf(info_text, | |
8213 | 684 "<b>%s:</b> %s<br/>", |
7014 | 685 _("Middle Name"), text2); |
686 } | |
687 g_free(text2); | |
688 } | |
689 } else if(text && !strcmp(child->name, "NICKNAME")) { | |
690 serv_got_alias(js->gc, from, text); | |
7955 | 691 if(b) { |
692 gaim_blist_node_set_string((GaimBlistNode*)b, "servernick", text); | |
693 } | |
8213 | 694 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 695 _("Nickname"), text); |
696 } else if(text && !strcmp(child->name, "BDAY")) { | |
8213 | 697 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 698 _("Birthday"), text); |
699 } else if(!strcmp(child->name, "ADR")) { | |
700 /* show which address it is */ | |
701 if(child->child) | |
8213 | 702 g_string_append_printf(info_text, "<b>%s:</b><br/>", |
7014 | 703 _("Address")); |
704 for(child2 = child->child; child2; child2 = child2->next) | |
705 { | |
706 char *text2; | |
707 | |
8135 | 708 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 709 continue; |
710 | |
711 text2 = xmlnode_get_data(child2); | |
712 if(text2 && !strcmp(child2->name, "POBOX")) { | |
713 g_string_append_printf(info_text, | |
8213 | 714 " <b>%s:</b> %s<br/>", |
7014 | 715 _("P.O. Box"), text2); |
716 } else if(text2 && !strcmp(child2->name, "EXTADR")) { | |
717 g_string_append_printf(info_text, | |
8213 | 718 " <b>%s:</b> %s<br/>", |
7014 | 719 _("Extended Address"), text2); |
720 } else if(text2 && !strcmp(child2->name, "STREET")) { | |
721 g_string_append_printf(info_text, | |
8213 | 722 " <b>%s:</b> %s<br/>", |
7014 | 723 _("Street Address"), text2); |
724 } else if(text2 && !strcmp(child2->name, "LOCALITY")) { | |
725 g_string_append_printf(info_text, | |
8213 | 726 " <b>%s:</b> %s<br/>", |
7014 | 727 _("Locality"), text2); |
728 } else if(text2 && !strcmp(child2->name, "REGION")) { | |
729 g_string_append_printf(info_text, | |
8213 | 730 " <b>%s:</b> %s<br/>", |
7014 | 731 _("Region"), text2); |
732 } else if(text2 && !strcmp(child2->name, "PCODE")) { | |
733 g_string_append_printf(info_text, | |
8213 | 734 " <b>%s:</b> %s<br/>", |
7014 | 735 _("Postal Code"), text2); |
736 } else if(text2 && (!strcmp(child2->name, "CTRY") | |
737 || !strcmp(child2->name, "COUNTRY"))) { | |
738 g_string_append_printf(info_text, | |
8213 | 739 " <b>%s:</b> %s<br/>", |
7014 | 740 _("Country"), text2); |
741 } | |
742 g_free(text2); | |
743 } | |
744 } else if(!strcmp(child->name, "TEL")) { | |
745 char *number; | |
746 if((child2 = xmlnode_get_child(child, "NUMBER"))) { | |
747 /* show what kind of number it is */ | |
748 number = xmlnode_get_data(child2); | |
749 if(number) { | |
750 g_string_append_printf(info_text, | |
8213 | 751 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 752 g_free(number); |
753 } | |
754 } else if((number = xmlnode_get_data(child))) { | |
755 /* lots of clients (including gaim) do this, but it's | |
756 * out of spec */ | |
757 g_string_append_printf(info_text, | |
8213 | 758 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 759 g_free(number); |
760 } | |
761 } else if(!strcmp(child->name, "EMAIL")) { | |
762 char *userid; | |
763 if((child2 = xmlnode_get_child(child, "USERID"))) { | |
764 /* show what kind of email it is */ | |
765 userid = xmlnode_get_data(child2); | |
766 if(userid) { | |
767 g_string_append_printf(info_text, | |
8213 | 768 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
7014 | 769 _("Email"), userid, userid); |
770 g_free(userid); | |
771 } | |
772 } else if((userid = xmlnode_get_data(child))) { | |
773 /* lots of clients (including gaim) do this, but it's | |
774 * out of spec */ | |
775 g_string_append_printf(info_text, | |
8213 | 776 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
7014 | 777 _("Email"), userid, userid); |
778 g_free(userid); | |
779 } | |
780 } else if(!strcmp(child->name, "ORG")) { | |
781 for(child2 = child->child; child2; child2 = child2->next) | |
782 { | |
783 char *text2; | |
784 | |
8135 | 785 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 786 continue; |
787 | |
788 text2 = xmlnode_get_data(child2); | |
789 if(text2 && !strcmp(child2->name, "ORGNAME")) { | |
790 g_string_append_printf(info_text, | |
8213 | 791 "<b>%s:</b> %s<br/>", |
7014 | 792 _("Organization Name"), text2); |
793 } else if(text2 && !strcmp(child2->name, "ORGUNIT")) { | |
794 g_string_append_printf(info_text, | |
8213 | 795 "<b>%s:</b> %s<br/>", |
7014 | 796 _("Organization Unit"), text2); |
797 } | |
798 g_free(text2); | |
799 } | |
800 } else if(text && !strcmp(child->name, "TITLE")) { | |
8213 | 801 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 802 _("Title"), text); |
803 } else if(text && !strcmp(child->name, "ROLE")) { | |
8213 | 804 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 805 _("Role"), text); |
806 } else if(text && !strcmp(child->name, "DESC")) { | |
8213 | 807 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
808 _("Description"), text); | |
7076 | 809 } else if(!strcmp(child->name, "PHOTO") || |
810 !strcmp(child->name, "LOGO")) { | |
10941 | 811 char *bintext = NULL; |
812 xmlnode *binval; | |
11361 | 813 |
814 if( ((binval = xmlnode_get_child(child, "BINVAL")) && | |
815 (bintext = xmlnode_get_data(binval))) || | |
816 (bintext = xmlnode_get_data(child))) { | |
11127 | 817 gsize size; |
11137 | 818 guchar *data; |
11127 | 819 int i; |
10941 | 820 unsigned char hashval[20]; |
11127 | 821 char *p, hash[41]; |
10941 | 822 gboolean photo = (strcmp(child->name, "PHOTO") == 0); |
10189 | 823 |
11361 | 824 data = gaim_base64_decode(bintext, &size); |
7076 | 825 |
10941 | 826 imgids = g_slist_prepend(imgids, GINT_TO_POINTER(gaim_imgstore_add(data, size, "logo.png"))); |
827 g_string_append_printf(info_text, | |
828 "<b>%s:</b> <img id='%d'><br/>", | |
829 photo ? _("Photo") : _("Logo"), | |
830 GPOINTER_TO_INT(imgids->data)); | |
7076 | 831 |
10941 | 832 gaim_buddy_icons_set_for_user(js->gc->account, bare_jid, |
833 data, size); | |
10189 | 834 |
11183 | 835 gaim_cipher_digest_region("sha1", (guchar *)data, size, |
10941 | 836 sizeof(hashval), hashval, NULL); |
837 p = hash; | |
838 for(i=0; i<20; i++, p+=2) | |
839 snprintf(p, 3, "%02x", hashval[i]); | |
840 gaim_blist_node_set_string((GaimBlistNode*)b, "avatar_hash", hash); | |
10189 | 841 |
10941 | 842 g_free(data); |
843 g_free(bintext); | |
844 } | |
7014 | 845 } |
846 g_free(text); | |
847 } | |
848 } | |
849 | |
8213 | 850 text = gaim_strdup_withhtml(info_text->str); |
851 | |
11533
c9b815aeddc1
[gaim-migrate @ 13782]
Richard Laager <rlaager@wiktel.com>
parents:
11532
diff
changeset
|
852 gaim_notify_userinfo(js->gc, from, text, NULL, NULL); |
7014 | 853 |
10189 | 854 while(imgids) { |
855 gaim_imgstore_unref(GPOINTER_TO_INT(imgids->data)); | |
856 imgids = g_slist_delete_link(imgids, imgids); | |
857 } | |
7014 | 858 g_string_free(info_text, TRUE); |
8213 | 859 g_free(text); |
10189 | 860 g_free(bare_jid); |
7014 | 861 } |
862 | |
10189 | 863 static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *full_jid) |
7014 | 864 { |
865 JabberIq *iq; | |
866 xmlnode *vcard; | |
867 | |
868 iq = jabber_iq_new(js, JABBER_IQ_GET); | |
869 | |
10189 | 870 xmlnode_set_attrib(iq->node, "to", full_jid); |
7014 | 871 vcard = xmlnode_new_child(iq->node, "vCard"); |
872 xmlnode_set_attrib(vcard, "xmlns", "vcard-temp"); | |
873 | |
7395 | 874 jabber_iq_set_callback(iq, jabber_vcard_parse, NULL); |
7014 | 875 |
876 jabber_iq_send(iq); | |
877 } | |
878 | |
10189 | 879 void jabber_buddy_get_info(GaimConnection *gc, const char *who) |
880 { | |
881 JabberStream *js = gc->proto_data; | |
882 char *bare_jid = jabber_get_bare_jid(who); | |
883 | |
884 if(bare_jid) { | |
885 jabber_buddy_get_info_for_jid(js, bare_jid); | |
886 g_free(bare_jid); | |
887 } | |
888 } | |
889 | |
7014 | 890 void jabber_buddy_get_info_chat(GaimConnection *gc, int id, |
891 const char *resource) | |
892 { | |
893 JabberStream *js = gc->proto_data; | |
894 JabberChat *chat = jabber_chat_find_by_id(js, id); | |
895 char *full_jid; | |
896 | |
897 if(!chat) | |
898 return; | |
899 | |
900 full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, resource); | |
10189 | 901 jabber_buddy_get_info_for_jid(js, full_jid); |
7014 | 902 g_free(full_jid); |
903 } | |
904 | |
7395 | 905 |
7014 | 906 static void jabber_buddy_set_invisibility(JabberStream *js, const char *who, |
907 gboolean invisible) | |
908 { | |
9944 | 909 GaimPresence *gpresence; |
910 GaimAccount *account; | |
911 GaimStatus *status; | |
7014 | 912 JabberBuddy *jb = jabber_buddy_find(js, who, TRUE); |
913 xmlnode *presence; | |
9954 | 914 JabberBuddyState state; |
915 const char *msg; | |
916 int priority; | |
7014 | 917 |
9944 | 918 account = gaim_connection_get_account(js->gc); |
919 gpresence = gaim_account_get_presence(account); | |
920 status = gaim_presence_get_active_status(gpresence); | |
921 | |
9954 | 922 gaim_status_to_jabber(status, &state, &msg, &priority); |
923 presence = jabber_presence_create(state, msg, priority); | |
924 | |
7014 | 925 xmlnode_set_attrib(presence, "to", who); |
926 if(invisible) { | |
927 xmlnode_set_attrib(presence, "type", "invisible"); | |
928 jb->invisible |= JABBER_INVIS_BUDDY; | |
929 } else { | |
930 jb->invisible &= ~JABBER_INVIS_BUDDY; | |
931 } | |
932 | |
933 jabber_send(js, presence); | |
934 xmlnode_free(presence); | |
935 } | |
936 | |
9030 | 937 static void jabber_buddy_make_invisible(GaimBlistNode *node, gpointer data) |
7014 | 938 { |
9030 | 939 GaimBuddy *buddy; |
940 GaimConnection *gc; | |
941 JabberStream *js; | |
942 | |
943 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
944 | |
945 buddy = (GaimBuddy *) node; | |
946 gc = gaim_account_get_connection(buddy->account); | |
947 js = gc->proto_data; | |
948 | |
949 jabber_buddy_set_invisibility(js, buddy->name, TRUE); | |
7014 | 950 } |
951 | |
9030 | 952 static void jabber_buddy_make_visible(GaimBlistNode *node, gpointer data) |
7014 | 953 { |
9030 | 954 GaimBuddy *buddy; |
955 GaimConnection *gc; | |
956 JabberStream *js; | |
7014 | 957 |
9030 | 958 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); |
7014 | 959 |
9030 | 960 buddy = (GaimBuddy *) node; |
961 gc = gaim_account_get_connection(buddy->account); | |
962 js = gc->proto_data; | |
963 | |
964 jabber_buddy_set_invisibility(js, buddy->name, FALSE); | |
7014 | 965 } |
966 | |
9030 | 967 static void jabber_buddy_cancel_presence_notification(GaimBlistNode *node, |
968 gpointer data) | |
7014 | 969 { |
9030 | 970 GaimBuddy *buddy; |
971 GaimConnection *gc; | |
972 JabberStream *js; | |
973 | |
974 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7014 | 975 |
9030 | 976 buddy = (GaimBuddy *) node; |
977 gc = gaim_account_get_connection(buddy->account); | |
978 js = gc->proto_data; | |
979 | |
980 /* I wonder if we should prompt the user before doing this */ | |
981 jabber_presence_subscription_set(js, buddy->name, "unsubscribed"); | |
7014 | 982 } |
983 | |
9030 | 984 static void jabber_buddy_rerequest_auth(GaimBlistNode *node, gpointer data) |
7250 | 985 { |
9030 | 986 GaimBuddy *buddy; |
987 GaimConnection *gc; | |
988 JabberStream *js; | |
989 | |
990 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7250 | 991 |
9030 | 992 buddy = (GaimBuddy *) node; |
993 gc = gaim_account_get_connection(buddy->account); | |
994 js = gc->proto_data; | |
995 | |
996 jabber_presence_subscription_set(js, buddy->name, "subscribe"); | |
7250 | 997 } |
998 | |
9030 | 999 |
1000 static void jabber_buddy_unsubscribe(GaimBlistNode *node, gpointer data) | |
7014 | 1001 { |
9030 | 1002 GaimBuddy *buddy; |
1003 GaimConnection *gc; | |
1004 JabberStream *js; | |
1005 | |
1006 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
1007 | |
1008 buddy = (GaimBuddy *) node; | |
1009 gc = gaim_account_get_connection(buddy->account); | |
1010 js = gc->proto_data; | |
1011 | |
1012 jabber_presence_subscription_set(js, buddy->name, "unsubscribe"); | |
1013 } | |
1014 | |
1015 | |
12323
fc464a0abccc
[gaim-migrate @ 14627]
Richard Laager <rlaager@wiktel.com>
parents:
12284
diff
changeset
|
1016 static GList *jabber_buddy_menu(GaimBuddy *buddy) |
9030 | 1017 { |
1018 GaimConnection *gc = gaim_account_get_connection(buddy->account); | |
1019 JabberStream *js = gc->proto_data; | |
1020 JabberBuddy *jb = jabber_buddy_find(js, buddy->name, TRUE); | |
1021 | |
7014 | 1022 GList *m = NULL; |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1023 GaimMenuAction *act; |
7395 | 1024 |
1025 if(!jb) | |
1026 return m; | |
1027 | |
8185 | 1028 /* XXX: fix the NOT ME below */ |
1029 | |
1030 if(js->protocol_version == JABBER_PROTO_0_9 /* && NOT ME */) { | |
8166 | 1031 if(jb->invisible & JABBER_INVIS_BUDDY) { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1032 act = gaim_menu_action_new(_("Un-hide From"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1033 GAIM_CALLBACK(jabber_buddy_make_visible), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1034 NULL, NULL); |
8166 | 1035 } else { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1036 act = gaim_menu_action_new(_("Temporarily Hide From"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1037 GAIM_CALLBACK(jabber_buddy_make_invisible), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1038 NULL, NULL); |
8166 | 1039 } |
9030 | 1040 m = g_list_append(m, act); |
7014 | 1041 } |
1042 | |
8185 | 1043 if(jb->subscription & JABBER_SUB_FROM /* && NOT ME */) { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1044 act = gaim_menu_action_new(_("Cancel Presence Notification"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1045 GAIM_CALLBACK(jabber_buddy_cancel_presence_notification), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1046 NULL, NULL); |
9030 | 1047 m = g_list_append(m, act); |
7014 | 1048 } |
1049 | |
1050 if(!(jb->subscription & JABBER_SUB_TO)) { | |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1051 act = gaim_menu_action_new(_("(Re-)Request authorization"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1052 GAIM_CALLBACK(jabber_buddy_rerequest_auth), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1053 NULL, NULL); |
9030 | 1054 m = g_list_append(m, act); |
1055 | |
8185 | 1056 } else /* if(NOT ME) */{ |
9030 | 1057 |
1058 /* shouldn't this just happen automatically when the buddy is | |
1059 removed? */ | |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1060 act = gaim_menu_action_new(_("Unsubscribe"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1061 GAIM_CALLBACK(jabber_buddy_unsubscribe), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1062 NULL, NULL); |
9030 | 1063 m = g_list_append(m, act); |
7014 | 1064 } |
1065 | |
1066 return m; | |
1067 } | |
9030 | 1068 |
1069 GList * | |
1070 jabber_blist_node_menu(GaimBlistNode *node) | |
1071 { | |
1072 if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
1073 return jabber_buddy_menu((GaimBuddy *) node); | |
1074 } else { | |
1075 return NULL; | |
1076 } | |
1077 } | |
1078 | |
1079 | |
9954 | 1080 const char * |
1081 jabber_buddy_state_get_name(JabberBuddyState state) | |
1082 { | |
1083 switch(state) { | |
1084 case JABBER_BUDDY_STATE_UNKNOWN: | |
1085 return _("Unknown"); | |
1086 case JABBER_BUDDY_STATE_ERROR: | |
1087 return _("Error"); | |
1088 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1089 return _("Offline"); | |
1090 case JABBER_BUDDY_STATE_ONLINE: | |
12467
1b57012eec7b
[gaim-migrate @ 14777]
Richard Laager <rlaager@wiktel.com>
parents:
12323
diff
changeset
|
1091 return _("Available"); |
9954 | 1092 case JABBER_BUDDY_STATE_CHAT: |
1093 return _("Chatty"); | |
1094 case JABBER_BUDDY_STATE_AWAY: | |
1095 return _("Away"); | |
1096 case JABBER_BUDDY_STATE_XA: | |
1097 return _("Extended Away"); | |
1098 case JABBER_BUDDY_STATE_DND: | |
1099 return _("Do Not Disturb"); | |
1100 } | |
1101 | |
1102 return _("Unknown"); | |
1103 } | |
1104 | |
1105 JabberBuddyState jabber_buddy_status_id_get_state(const char *id) { | |
1106 if(!id) | |
1107 return JABBER_BUDDY_STATE_UNKNOWN; | |
11540 | 1108 if(!strcmp(id, "available")) |
9954 | 1109 return JABBER_BUDDY_STATE_ONLINE; |
12683 | 1110 if(!strcmp(id, "freeforchat")) |
1111 return JABBER_BUDDY_STATE_CHAT; | |
1112 if(!strcmp(id, "away")) | |
1113 return JABBER_BUDDY_STATE_AWAY; | |
1114 if(!strcmp(id, "extended_away")) | |
1115 return JABBER_BUDDY_STATE_XA; | |
1116 if(!strcmp(id, "dnd")) | |
1117 return JABBER_BUDDY_STATE_DND; | |
1118 if(!strcmp(id, "offline")) | |
1119 return JABBER_BUDDY_STATE_UNAVAILABLE; | |
1120 if(!strcmp(id, "error")) | |
1121 return JABBER_BUDDY_STATE_ERROR; | |
1122 | |
1123 return JABBER_BUDDY_STATE_UNKNOWN; | |
1124 } | |
1125 | |
1126 JabberBuddyState jabber_buddy_show_get_state(const char *id) { | |
1127 if(!id) | |
1128 return JABBER_BUDDY_STATE_UNKNOWN; | |
1129 if(!strcmp(id, "available")) | |
1130 return JABBER_BUDDY_STATE_ONLINE; | |
9954 | 1131 if(!strcmp(id, "chat")) |
1132 return JABBER_BUDDY_STATE_CHAT; | |
1133 if(!strcmp(id, "away")) | |
1134 return JABBER_BUDDY_STATE_AWAY; | |
1135 if(!strcmp(id, "xa")) | |
1136 return JABBER_BUDDY_STATE_XA; | |
1137 if(!strcmp(id, "dnd")) | |
1138 return JABBER_BUDDY_STATE_DND; | |
1139 if(!strcmp(id, "offline")) | |
1140 return JABBER_BUDDY_STATE_UNAVAILABLE; | |
1141 if(!strcmp(id, "error")) | |
1142 return JABBER_BUDDY_STATE_ERROR; | |
1143 | |
1144 return JABBER_BUDDY_STATE_UNKNOWN; | |
1145 } | |
1146 | |
12683 | 1147 const char *jabber_buddy_state_get_show(JabberBuddyState state) { |
9954 | 1148 switch(state) { |
1149 case JABBER_BUDDY_STATE_CHAT: | |
1150 return "chat"; | |
1151 case JABBER_BUDDY_STATE_AWAY: | |
1152 return "away"; | |
1153 case JABBER_BUDDY_STATE_XA: | |
1154 return "xa"; | |
1155 case JABBER_BUDDY_STATE_DND: | |
1156 return "dnd"; | |
1157 case JABBER_BUDDY_STATE_ONLINE: | |
11540 | 1158 return "available"; |
9954 | 1159 case JABBER_BUDDY_STATE_UNKNOWN: |
1160 case JABBER_BUDDY_STATE_ERROR: | |
1161 return NULL; | |
1162 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1163 return "offline"; | |
1164 } | |
1165 return NULL; | |
1166 } | |
11675 | 1167 |
12683 | 1168 const char *jabber_buddy_state_get_status_id(JabberBuddyState state) { |
1169 switch(state) { | |
1170 case JABBER_BUDDY_STATE_CHAT: | |
1171 return "freeforchat"; | |
1172 case JABBER_BUDDY_STATE_AWAY: | |
1173 return "away"; | |
1174 case JABBER_BUDDY_STATE_XA: | |
1175 return "extended_away"; | |
1176 case JABBER_BUDDY_STATE_DND: | |
1177 return "dnd"; | |
1178 case JABBER_BUDDY_STATE_ONLINE: | |
1179 return "available"; | |
1180 case JABBER_BUDDY_STATE_UNKNOWN: | |
1181 case JABBER_BUDDY_STATE_ERROR: | |
1182 return NULL; | |
1183 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1184 return "offline"; | |
1185 } | |
1186 return NULL; | |
1187 } | |
1188 | |
11675 | 1189 static void user_search_result_add_buddy_cb(GaimConnection *gc, GList *row) |
1190 { | |
1191 /* XXX find out the jid */ | |
1192 gaim_blist_request_add_buddy(gaim_connection_get_account(gc), | |
1193 g_list_nth_data(row, 0), NULL, NULL); | |
1194 } | |
1195 | |
1196 static void user_search_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
1197 { | |
1198 GaimNotifySearchResults *results; | |
1199 GaimNotifySearchColumn *column; | |
1200 xmlnode *x, *query, *item, *field; | |
1201 | |
1202 /* XXX error checking? */ | |
1203 if(!(query = xmlnode_get_child(packet, "query"))) | |
1204 return; | |
1205 | |
1206 results = gaim_notify_searchresults_new(); | |
1207 if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) { | |
1208 xmlnode *reported; | |
1209 gaim_debug_info("jabber", "new-skool\n"); | |
1210 if((reported = xmlnode_get_child(x, "reported"))) { | |
1211 xmlnode *field = xmlnode_get_child(reported, "field"); | |
1212 while(field) { | |
1213 /* XXX keep track of this order, use it below */ | |
1214 const char *var = xmlnode_get_attrib(field, "var"); | |
1215 const char *label = xmlnode_get_attrib(field, "label"); | |
1216 if(var) { | |
1217 column = gaim_notify_searchresults_column_new(label ? label : var); | |
1218 gaim_notify_searchresults_column_add(results, column); | |
1219 } | |
1220 field = xmlnode_get_next_twin(field); | |
1221 } | |
1222 } | |
1223 item = xmlnode_get_child(x, "item"); | |
1224 while(item) { | |
1225 GList *row = NULL; | |
1226 field = xmlnode_get_child(item, "field"); | |
1227 while(field) { | |
1228 xmlnode *valuenode = xmlnode_get_child(item, "value"); | |
1229 if(valuenode) { | |
1230 char *value = xmlnode_get_data(valuenode); | |
1231 row = g_list_append(row, value); | |
1232 } | |
1233 field = xmlnode_get_next_twin(field); | |
1234 } | |
1235 gaim_notify_searchresults_row_add(results, row); | |
1236 | |
1237 item = xmlnode_get_next_twin(item); | |
1238 } | |
1239 } else { | |
1240 /* old skool */ | |
1241 gaim_debug_info("jabber", "old-skool\n"); | |
1242 | |
1243 column = gaim_notify_searchresults_column_new("JID"); | |
1244 gaim_notify_searchresults_column_add(results, column); | |
1245 column = gaim_notify_searchresults_column_new("First"); | |
1246 gaim_notify_searchresults_column_add(results, column); | |
1247 column = gaim_notify_searchresults_column_new("Last"); | |
1248 gaim_notify_searchresults_column_add(results, column); | |
1249 column = gaim_notify_searchresults_column_new("Nickname"); | |
1250 gaim_notify_searchresults_column_add(results, column); | |
1251 column = gaim_notify_searchresults_column_new("E-Mail"); | |
1252 gaim_notify_searchresults_column_add(results, column); | |
1253 | |
1254 for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) { | |
1255 const char *jid; | |
1256 xmlnode *node; | |
1257 GList *row = NULL; | |
1258 | |
1259 if(!(jid = xmlnode_get_attrib(item, "jid"))) | |
1260 continue; | |
1261 | |
1262 row = g_list_append(row, g_strdup(jid)); | |
1263 node = xmlnode_get_child(item, "first"); | |
1264 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1265 node = xmlnode_get_child(item, "last"); | |
1266 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1267 node = xmlnode_get_child(item, "nick"); | |
1268 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1269 node = xmlnode_get_child(item, "email"); | |
1270 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1271 gaim_debug_info("jabber", "row=%d\n", row); | |
1272 gaim_notify_searchresults_row_add(results, row); | |
1273 } | |
1274 } | |
1275 | |
12624
851b0bd7eb52
[gaim-migrate @ 14960]
Christopher O'Brien <siege@pidgin.im>
parents:
12467
diff
changeset
|
1276 gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_ADD, |
11675 | 1277 user_search_result_add_buddy_cb); |
1278 | |
1279 gaim_notify_searchresults(js->gc, NULL, NULL, _("The following are the results of your search"), results, NULL, NULL); | |
1280 } | |
1281 | |
1282 static void user_search_x_data_cb(JabberStream *js, xmlnode *result, gpointer data) | |
1283 { | |
1284 xmlnode *query; | |
1285 JabberIq *iq; | |
1286 | |
1287 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search"); | |
1288 query = xmlnode_get_child(iq->node, "query"); | |
1289 | |
1290 xmlnode_insert_child(query, result); | |
1291 | |
1292 jabber_iq_set_callback(iq, user_search_result_cb, NULL); | |
1293 jabber_iq_send(iq); | |
1294 } | |
1295 | |
1296 struct user_search_info { | |
1297 JabberStream *js; | |
1298 char *directory_server; | |
1299 }; | |
1300 | |
1301 static void user_search_cancel_cb(struct user_search_info *usi, GaimRequestFields *fields) | |
1302 { | |
1303 g_free(usi->directory_server); | |
1304 g_free(usi); | |
1305 } | |
1306 | |
1307 static void user_search_cb(struct user_search_info *usi, GaimRequestFields *fields) | |
1308 { | |
1309 JabberStream *js = usi->js; | |
1310 JabberIq *iq; | |
1311 xmlnode *query; | |
1312 GList *groups, *flds; | |
1313 | |
1314 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search"); | |
1315 query = xmlnode_get_child(iq->node, "query"); | |
1316 | |
1317 for(groups = gaim_request_fields_get_groups(fields); groups; groups = groups->next) { | |
1318 for(flds = gaim_request_field_group_get_fields(groups->data); | |
1319 flds; flds = flds->next) { | |
1320 GaimRequestField *field = flds->data; | |
1321 const char *id = gaim_request_field_get_id(field); | |
1322 const char *value = gaim_request_field_string_get_value(field); | |
1323 | |
1324 if(value && (!strcmp(id, "first") || !strcmp(id, "last") || !strcmp(id, "nick") || !strcmp(id, "email"))) { | |
1325 xmlnode *y = xmlnode_new_child(query, id); | |
1326 xmlnode_insert_data(y, value, -1); | |
1327 } | |
1328 } | |
1329 } | |
1330 | |
1331 jabber_iq_set_callback(iq, user_search_result_cb, NULL); | |
1332 xmlnode_set_attrib(iq->node, "to", usi->directory_server); | |
1333 jabber_iq_send(iq); | |
1334 | |
1335 g_free(usi->directory_server); | |
1336 g_free(usi); | |
1337 } | |
1338 | |
1339 static void user_search_fields_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
1340 { | |
1341 xmlnode *query, *x; | |
1342 const char *from; | |
1343 | |
1344 /* i forget, do i have to check for error? XXX */ | |
12284
ecd471d1eeec
[gaim-migrate @ 14588]
Etan Reisner <pidgin@unreliablesource.net>
parents:
11675
diff
changeset
|
1345 if(!(from = xmlnode_get_attrib(packet, "from"))) |
11675 | 1346 return; |
1347 | |
1348 | |
1349 if(!(query = xmlnode_get_child(packet, "query"))) | |
1350 return; | |
1351 | |
1352 if((x = xmlnode_get_child_with_namespace(packet, "x", "jabber:x:data"))) { | |
1353 jabber_x_data_request(js, x, user_search_x_data_cb, NULL); | |
1354 return; | |
1355 } else { | |
1356 struct user_search_info *usi; | |
1357 xmlnode *instnode; | |
1358 char *instructions; | |
1359 GaimRequestFields *fields; | |
1360 GaimRequestFieldGroup *group; | |
1361 GaimRequestField *field; | |
1362 | |
1363 /* old skool */ | |
1364 fields = gaim_request_fields_new(); | |
1365 group = gaim_request_field_group_new(NULL); | |
1366 gaim_request_fields_add_group(fields, group); | |
1367 | |
1368 if((instnode = xmlnode_get_child(query, "instructions"))) | |
1369 instructions = xmlnode_get_data(instnode); | |
1370 else | |
1371 instructions = g_strdup(_("Fill in one or more fields to search " | |
1372 "for any matching Jabber users.")); | |
1373 | |
1374 if(xmlnode_get_child(query, "first")) { | |
1375 field = gaim_request_field_string_new("first", _("First Name"), | |
1376 NULL, FALSE); | |
1377 gaim_request_field_group_add_field(group, field); | |
1378 } | |
1379 if(xmlnode_get_child(query, "last")) { | |
1380 field = gaim_request_field_string_new("last", _("Last Name"), | |
1381 NULL, FALSE); | |
1382 gaim_request_field_group_add_field(group, field); | |
1383 } | |
1384 if(xmlnode_get_child(query, "nick")) { | |
1385 field = gaim_request_field_string_new("nick", _("Nickname"), | |
1386 NULL, FALSE); | |
1387 gaim_request_field_group_add_field(group, field); | |
1388 } | |
1389 if(xmlnode_get_child(query, "email")) { | |
1390 field = gaim_request_field_string_new("email", _("E-Mail Address"), | |
1391 NULL, FALSE); | |
1392 gaim_request_field_group_add_field(group, field); | |
1393 } | |
1394 | |
1395 usi = g_new0(struct user_search_info, 1); | |
1396 usi->js = js; | |
1397 usi->directory_server = g_strdup(from); | |
1398 | |
1399 gaim_request_fields(js->gc, _("Search for Jabber users"), | |
1400 _("Search for Jabber users"), instructions, fields, | |
1401 _("Search"), G_CALLBACK(user_search_cb), | |
1402 _("Cancel"), G_CALLBACK(user_search_cancel_cb), usi); | |
1403 | |
1404 g_free(instructions); | |
1405 } | |
1406 } | |
1407 | |
1408 static void jabber_user_search_ok(JabberStream *js, const char *directory) | |
1409 { | |
1410 JabberIq *iq; | |
1411 | |
1412 /* XXX: should probably better validate the directory we're given */ | |
1413 if(!directory || !*directory) { | |
1414 gaim_notify_error(js->gc, _("Invalid Directory"), _("Invalid Directory"), NULL); | |
1415 return; | |
1416 } | |
1417 | |
1418 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:search"); | |
1419 xmlnode_set_attrib(iq->node, "to", directory); | |
1420 | |
1421 jabber_iq_set_callback(iq, user_search_fields_result_cb, NULL); | |
1422 | |
1423 jabber_iq_send(iq); | |
1424 } | |
1425 | |
1426 void jabber_user_search_begin(GaimPluginAction *action) | |
1427 { | |
1428 GaimConnection *gc = (GaimConnection *) action->context; | |
1429 JabberStream *js = gc->proto_data; | |
1430 | |
1431 gaim_request_input(gc, _("Enter a User Directory"), _("Enter a User Directory"), | |
1432 _("Select a user directory to search"), | |
1433 js->user_directories ? js->user_directories->data : "users.jabber.org", | |
1434 FALSE, FALSE, NULL, | |
1435 _("Search Directory"), GAIM_CALLBACK(jabber_user_search_ok), | |
1436 _("Cancel"), NULL, js); | |
1437 } |