Mercurial > pidgin
annotate src/protocols/jabber/jabber.c @ 4966:54cd43869333
[gaim-migrate @ 5300]
fun stuff
this makes the modify account dialog make a little more sense for jabber,
and makes irc accounts distinguishable in the assorted dropdowns.
however, there is a slight catch. IRC accounts now take the form of
nick@server. The first time you log on with an IRC account, it will change
it for you. However, if you try to edit the account before it gets signed
on, the server will revert to the default (irc.freenode.net).
So go log in with all of your IRC accounts before you go editing them ;-)
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Thu, 03 Apr 2003 02:34:48 +0000 |
parents | af89e6b99c1a |
children | fb232515839a |
rev | line source |
---|---|
2086 | 1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
2 /* | |
3 * gaim | |
4 * | |
5 * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
6 * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx> | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 * | |
21 */ | |
22 #ifdef HAVE_CONFIG_H | |
3630 | 23 #include <config.h> |
2086 | 24 #endif |
25 | |
3664 | 26 #include <sys/types.h> |
27 /*this must happen before sys/socket.h or freebsd won't compile*/ | |
28 | |
3630 | 29 #ifndef _WIN32 |
2086 | 30 #include <netdb.h> |
31 #include <netinet/in.h> | |
32 #include <arpa/inet.h> | |
3630 | 33 #include <sys/socket.h> |
34 #include <sys/utsname.h> | |
35 #include <unistd.h> | |
36 #else | |
37 #include "utsname.h" | |
38 #endif | |
39 | |
40 #include <errno.h> | |
2086 | 41 #include <string.h> |
42 #include <stdlib.h> | |
43 #include <stdio.h> | |
44 #include <time.h> | |
45 #include <sys/stat.h> | |
4608 | 46 #include "gaim.h" |
2086 | 47 #include "multi.h" |
48 #include "prpl.h" | |
2232
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
49 #ifdef MAX |
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
50 #undef MAX |
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
51 #endif |
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
52 #ifdef MIN |
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
53 #undef MIN |
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
54 #endif |
2086 | 55 #include "jabber.h" |
56 #include "proxy.h" | |
57 | |
3630 | 58 #ifdef _WIN32 |
59 #include "win32dep.h" | |
60 #endif | |
61 | |
4249 | 62 static struct prpl *my_protocol = NULL; |
63 | |
3630 | 64 /* for win32 compatability */ |
65 G_MODULE_IMPORT GSList *connections; | |
66 | |
2086 | 67 /* The priv member of gjconn's is a gaim_connection for now. */ |
68 #define GJ_GC(x) ((struct gaim_connection *)(x)->priv) | |
4249 | 69 /* Confused? That makes three of us. -Robot101 */ |
70 #define GC_GJ(x) ((gjconn)((struct jabber_data *)(x)->proto_data)->gjc) | |
2086 | 71 |
72 #define IQID_AUTH "__AUTH__" | |
73 | |
74 #define IQ_NONE -1 | |
75 #define IQ_AUTH 0 | |
76 #define IQ_ROSTER 1 | |
77 | |
3259 | 78 #define UC_AWAY (0x02 | UC_UNAVAILABLE) |
79 #define UC_CHAT 0x04 | |
80 #define UC_XA (0x08 | UC_UNAVAILABLE) | |
81 #define UC_DND (0x10 | UC_UNAVAILABLE) | |
82 #define UC_ERROR (0x20 | UC_UNAVAILABLE) | |
2086 | 83 |
4917 | 84 #define DEFAULT_SERVER "jabber.org" |
2086 | 85 #define DEFAULT_GROUPCHAT "conference.jabber.org" |
86 #define DEFAULT_PORT 5222 | |
87 | |
88 #define USEROPT_PORT 0 | |
4436 | 89 #define USEROPT_CONN_SERVER 1 |
2086 | 90 |
3311 | 91 #define JABBER_TYPING_NOTIFY_INT 15 /* Delay (in seconds) between sending typing notifications */ |
92 | |
4450 | 93 #define JABBER_KEEPALIVE_STRING " \t " |
94 | |
3074 | 95 /* |
96 * Note: "was_connected" may seem redundant, but it was needed and I | |
97 * didn't want to touch the Jabber state stuff not specific to Gaim. | |
98 */ | |
2086 | 99 typedef struct gjconn_struct { |
100 /* Core structure */ | |
101 pool p; /* Memory allocation pool */ | |
102 int state; /* Connection state flag */ | |
3074 | 103 int was_connected; /* We were once connected */ |
2086 | 104 int fd; /* Connection file descriptor */ |
105 jid user; /* User info */ | |
106 char *pass; /* User passwd */ | |
107 | |
108 /* Stream stuff */ | |
109 int id; /* id counter for jab_getid() function */ | |
110 char idbuf[9]; /* temporary storage for jab_getid() */ | |
111 char *sid; /* stream id from server, for digest auth */ | |
112 XML_Parser parser; /* Parser instance */ | |
113 xmlnode current; /* Current node in parsing instance.. */ | |
114 | |
115 /* Event callback ptrs */ | |
2956 | 116 void (*on_state)(struct gjconn_struct *gjc, int state); |
117 void (*on_packet)(struct gjconn_struct *gjc, jpacket p); | |
118 | |
119 GHashTable *queries; /* query tracker */ | |
2086 | 120 |
121 void *priv; | |
122 | |
123 } *gjconn, gjconn_struct; | |
124 | |
2956 | 125 typedef void (*gjconn_state_h)(gjconn gjc, int state); |
126 typedef void (*gjconn_packet_h)(gjconn gjc, jpacket p); | |
2086 | 127 |
128 static gjconn gjab_new(char *user, char *pass, void *priv); | |
2956 | 129 static void gjab_delete(gjconn gjc); |
130 static void gjab_state_handler(gjconn gjc, gjconn_state_h h); | |
131 static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h); | |
132 static void gjab_start(gjconn gjc); | |
133 static void gjab_stop(gjconn gjc); | |
2086 | 134 /* |
2956 | 135 static int gjab_getfd(gjconn gjc); |
136 static jid gjab_getjid(gjconn gjc); | |
137 static char *gjab_getsid(gjconn gjc); | |
2086 | 138 */ |
2956 | 139 static char *gjab_getid(gjconn gjc); |
140 static void gjab_send(gjconn gjc, xmlnode x); | |
141 static void gjab_send_raw(gjconn gjc, const char *str); | |
142 static void gjab_recv(gjconn gjc); | |
143 static void gjab_auth(gjconn gjc); | |
144 | |
145 /* | |
146 * It is *this* to which we point the gaim_connection proto_data | |
147 */ | |
2086 | 148 struct jabber_data { |
2956 | 149 gjconn gjc; |
2086 | 150 gboolean did_import; |
2956 | 151 GSList *chats; |
2086 | 152 time_t idle; |
2800
0ad63a625eec
[gaim-migrate @ 2813]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2791
diff
changeset
|
153 gboolean die; |
3311 | 154 GHashTable *buddies; |
3630 | 155 GSList *file_transfers; |
2086 | 156 }; |
157 | |
2956 | 158 /* |
3340 | 159 * Used in jabber_buddy_data.invisible, below |
160 */ | |
161 #define JABBER_NOT_INVIS 0x00 | |
162 #define JABBER_SERV_INVIS 0x01 /* Invisible set on server */ | |
163 #define JABBER_BUD_INVIS 0x02 /* Invisible set on buddy */ | |
164 | |
165 /* | |
4927 | 166 * Used in jabber_buddy_data.subscription, below |
167 */ | |
168 #define JABBER_SUB_NONE 0x0 | |
169 #define JABBER_SUB_PENDING 0x1 | |
170 #define JABBER_SUB_TO 0x2 | |
171 #define JABBER_SUB_FROM 0x4 | |
172 #define JABBER_SUB_BOTH (JABBER_SUB_TO | JABBER_SUB_FROM) | |
173 | |
174 | |
175 /* | |
3311 | 176 * It is *this* to which we point the buddy proto_data |
177 */ | |
178 struct jabber_buddy_data { | |
179 GSList *resources; | |
180 char *error_msg; | |
3340 | 181 unsigned invisible; /* We've set presence type invisible for this buddy */ |
4927 | 182 unsigned subscription; /* subscription type for this buddy */ |
3311 | 183 }; |
184 | |
185 /* | |
186 * per-resource info | |
187 */ | |
188 typedef struct jabber_resource_info { | |
3770 | 189 char *name; |
3311 | 190 int priority; |
191 int state; | |
192 char *away_msg; | |
193 char *thread_id; | |
194 gboolean has_composing; | |
195 } *jab_res_info; | |
196 | |
197 /* | |
198 * For our own jid handling | |
199 * | |
200 * We do our own so we can cleanly parse buddy names | |
201 * (user@server/resource) and rid ourselves of the | |
202 * struct when we're done with it. The Jabber lib | |
203 * structs last the life of the pool--we frequently | |
204 * don't want that. | |
205 * | |
206 * We use the real jid structs so we can make use of | |
207 * jid_safe(), jid_cmp() and some others. | |
208 * | |
209 * BE CAREFUL using the Jabber lib routines. | |
210 * Many of them assume pool use and are not | |
211 * amenable to use with our own! | |
212 * | |
213 * We give them special names so we know, throughout | |
214 * the code, that they're not alloc'd out of pool | |
215 * memory and we can, and must, dispose of them when | |
216 * we're done with 'em. | |
217 */ | |
218 #define gaim_jid_struct jid_struct | |
219 typedef struct gaim_jid_struct *gaim_jid; | |
220 | |
221 /* | |
2956 | 222 * Jabber "chat group" info. Pointers to these go in jabber_data |
223 * pending and existing chats lists. | |
224 */ | |
2086 | 225 struct jabber_chat { |
3311 | 226 gaim_jid gjid; |
2086 | 227 struct gaim_connection *gc; |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
228 struct gaim_conversation *b; |
2086 | 229 int id; |
2956 | 230 int state; |
2086 | 231 }; |
232 | |
2956 | 233 /* |
234 * Jabber chat states... | |
235 * | |
236 * Note: due to a bug in one version of the Jabber server, subscriptions | |
237 * to chat groups aren't (always?) properly removed at the server. The | |
238 * result is clients receive Jabber "presence" notifications for JIDs | |
239 * they no longer care about. The problem with such vestigial notifies is | |
240 * that we really have no way of telling if it's vestigial or if it's a | |
241 * valid "buddy" presence notification. So we keep jabber_chat structs | |
242 * around after leaving a chat group and simply mark them "closed." That | |
243 * way we can test for such errant presence notifications. I.e.: if we | |
244 * get a presence notfication from a JID that matches a chat group JID, | |
245 * we disregard it. | |
246 */ | |
247 #define JCS_PENDING 1 /* pending */ | |
248 #define JCS_ACTIVE 2 /* active */ | |
249 #define JCS_CLOSED 3 /* closed */ | |
250 | |
251 | |
252 #define STATE_EVT(arg) if(gjc->on_state) { (gjc->on_state)(gjc, (arg) ); } | |
253 | |
254 static void jabber_handlevcard(gjconn, xmlnode, char *); | |
2086 | 255 |
3630 | 256 static char *jabber_normalize(const char *s); |
257 | |
2086 | 258 static char *create_valid_jid(const char *given, char *server, char *resource) |
259 { | |
260 char *valid; | |
4927 | 261 char *tmp; |
262 | |
263 if (!(tmp = strchr(given, '@'))) | |
2086 | 264 valid = g_strdup_printf("%s@%s/%s", given, server, resource); |
4927 | 265 else if (!strchr(tmp, '/')) |
2086 | 266 valid = g_strdup_printf("%s/%s", given, resource); |
267 else | |
268 valid = g_strdup(given); | |
269 | |
270 return valid; | |
271 } | |
272 | |
4915 | 273 |
3311 | 274 /* |
275 * Dispose of a gaim_jid_struct | |
276 */ | |
277 static void gaim_jid_free(gaim_jid gjid) | |
278 { | |
279 if(gjid) { | |
280 if(gjid->resource) | |
281 free(gjid->resource); | |
282 if(gjid->user) | |
283 free(gjid->user); | |
284 if(gjid->server) | |
285 free(gjid->server); | |
286 if(gjid->full) | |
287 free(gjid->full); | |
288 free(gjid); | |
289 } | |
290 } | |
291 | |
292 /* | |
293 * Create a new gjid struct | |
294 * | |
295 * Unlike jid_new(), also creates "full." | |
296 * | |
297 * Shamelessly copied, in part, from jid.c: jid_new() | |
298 * | |
299 * Caller is responsible for freeing the space allocated by this via | |
300 * gaim_jid_free(). | |
301 * | |
302 * JFIXME: Has a local declaration for jid.c:jid_safe(). I've put in a | |
303 * request to have that added to libjabber's lib.h file. (JSeymour) | |
304 */ | |
305 static gaim_jid gaim_jid_new(char *name) | |
306 { | |
307 extern jid jid_safe(jid); /* *retch* */ | |
308 | |
309 gaim_jid gjid = NULL; | |
310 | |
311 if(name && strlen(name)) { | |
312 char *server, *resource, *type, *str; | |
313 int full_len = 0; | |
314 | |
315 /* user@server/resource */ | |
316 | |
317 str = strdup(name); /* we mangle a copy */ | |
318 | |
319 gjid = calloc(1, sizeof(struct gaim_jid_struct)); | |
320 | |
321 if((resource = strstr(str, "/")) != NULL) { | |
322 *resource = '\0'; | |
323 ++resource; | |
324 if((full_len = strlen(resource)) > 0) { | |
325 gjid->resource = strdup(resource); | |
326 ++full_len; /* for later "/" addition */ | |
327 } | |
328 } else { | |
329 resource = str + strlen(str); /* point to end */ | |
330 } | |
331 | |
332 type = strstr(str, ":"); | |
333 if(type != NULL && type < resource) { | |
334 *type = '\0'; | |
335 ++type; | |
336 str = type; /* ignore the type: prefix */ | |
337 } | |
338 | |
339 server = strstr(str, "@"); | |
340 | |
341 /* | |
342 * if there's no @, it's just the server address | |
343 */ | |
344 if(server == NULL || server > resource) { | |
345 gjid->server = strdup(str); | |
346 full_len += strlen(str); | |
347 } else { | |
348 *server = '\0'; | |
349 ++server; | |
350 gjid->server = strdup(server); | |
351 full_len += strlen(server) + 1; /* account for later "@" */ | |
352 if(strlen(str) > 0) { | |
353 gjid->user = strdup(str); | |
354 full_len += strlen(str); | |
355 } | |
356 } | |
357 | |
358 free(str); | |
359 | |
360 if(!jid_safe(gjid)) { | |
361 gaim_jid_free(gjid); | |
362 gjid = NULL; | |
363 } else { | |
364 if(full_len) { | |
365 char *s = gjid->full = malloc(++full_len); | |
366 | |
367 if(gjid->user) { | |
368 strcpy(s, gjid->user); | |
369 s += strlen(gjid->user); | |
370 } | |
371 if(gjid->server) { | |
372 if(s > gjid->full) | |
373 *(s++) = '@'; | |
374 strcpy(s, gjid->server); | |
375 s += strlen(gjid->server); | |
376 } | |
377 if(gjid->resource) { | |
378 *(s++) = '/'; | |
379 strcpy(s, gjid->resource); | |
380 } | |
381 } | |
382 } | |
383 } | |
384 | |
385 return gjid; | |
386 } | |
387 | |
388 /* | |
389 * Get a "username@server" from unadorned "username" | |
390 * | |
391 * If there's no "@server" part and "who" doesn't match the | |
392 * gjconn server (which would indicate that "who" *is* the | |
393 * server in case of server messages), the gjconn server is | |
394 * appended. | |
395 * | |
396 * If incl_resource is TRUE (non-0), the returned string | |
397 * includes the "/resource" part (if it exists), otherwise not. | |
398 * | |
399 * Allocates space for returned string. Caller is | |
400 * responsible for freeing it with g_free(). | |
401 * | |
402 * If "gjid" is non-null, sets that as well. Caller is | |
403 * reponsible for freeing that via gaim_jid_free() when done | |
404 * with it. | |
405 */ | |
3466 | 406 static gchar *get_realwho(gjconn gjc, const char *who, int incl_resource, gaim_jid *gjid) |
3311 | 407 { |
408 gaim_jid my_gjid; | |
409 gchar *my_who; | |
410 gchar *realwho = NULL; | |
411 | |
412 if(!(who && who[0])) { | |
413 return NULL; | |
414 } | |
415 | |
416 /* | |
417 * Bare username and "username" not the server itself? | |
418 */ | |
419 if(!strchr(who, '@') && strcasecmp(who, gjc->user->server)) { | |
420 my_who = g_strdup_printf("%s@%s", who, gjc->user->server); | |
421 } else { | |
422 my_who = g_strdup(who); | |
423 } | |
424 | |
425 if((my_gjid = gaim_jid_new(my_who)) != NULL) { | |
426 /* | |
427 * If there's no "user" part, "who" was just the server or perhaps a transport (?) | |
428 */ | |
429 if(my_gjid->user) { | |
430 /* | |
431 * Include "/resource" bit? | |
432 */ | |
433 if(incl_resource) { | |
434 realwho = g_strdup(my_gjid->full); | |
435 } else { | |
436 realwho = g_strdup_printf("%s@%s", my_gjid->user, my_gjid->server); | |
437 } | |
438 } else { | |
439 realwho = g_strdup(my_gjid->server); | |
440 } | |
441 } | |
442 | |
443 g_free(my_who); | |
444 | |
445 if(gjid) { | |
446 *gjid = my_gjid; | |
447 } else { | |
448 gaim_jid_free(my_gjid); | |
449 } | |
450 | |
451 return realwho; | |
452 } | |
453 | |
2086 | 454 static gjconn gjab_new(char *user, char *pass, void *priv) |
455 { | |
456 pool p; | |
2956 | 457 gjconn gjc; |
2086 | 458 |
459 if (!user) | |
460 return (NULL); | |
461 | |
462 p = pool_new(); | |
463 if (!p) | |
464 return (NULL); | |
2956 | 465 gjc = pmalloc_x(p, sizeof(gjconn_struct), 0); |
466 if (!gjc) { | |
467 pool_free(p); /* no need for this anymore! */ | |
2086 | 468 return (NULL); |
2956 | 469 } |
470 gjc->p = p; | |
471 | |
3236 | 472 if((gjc->user = jid_new(p, user)) == NULL) { |
473 pool_free(p); /* no need for this anymore! */ | |
474 return (NULL); | |
475 } | |
3257 | 476 |
477 gjc->pass = strdup(pass); | |
2956 | 478 |
479 gjc->state = JCONN_STATE_OFF; | |
3074 | 480 gjc->was_connected = 0; |
2956 | 481 gjc->id = 1; |
482 gjc->fd = -1; | |
483 | |
484 gjc->priv = priv; | |
485 | |
486 return gjc; | |
2086 | 487 } |
488 | |
2956 | 489 static void gjab_delete(gjconn gjc) |
2086 | 490 { |
2956 | 491 if (!gjc) |
2086 | 492 return; |
493 | |
2956 | 494 gjab_stop(gjc); |
3257 | 495 free(gjc->pass); |
2956 | 496 pool_free(gjc->p); |
2086 | 497 } |
498 | |
2956 | 499 static void gjab_state_handler(gjconn gjc, gjconn_state_h h) |
2086 | 500 { |
2956 | 501 if (!gjc) |
2086 | 502 return; |
503 | |
2956 | 504 gjc->on_state = h; |
2086 | 505 } |
506 | |
2956 | 507 static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h) |
2086 | 508 { |
2956 | 509 if (!gjc) |
2086 | 510 return; |
511 | |
2956 | 512 gjc->on_packet = h; |
2086 | 513 } |
514 | |
2956 | 515 static void gjab_stop(gjconn gjc) |
2086 | 516 { |
2956 | 517 if (!gjc || gjc->state == JCONN_STATE_OFF) |
2086 | 518 return; |
519 | |
2956 | 520 gjab_send_raw(gjc, "</stream:stream>"); |
521 gjc->state = JCONN_STATE_OFF; | |
3074 | 522 gjc->was_connected = 0; |
2956 | 523 close(gjc->fd); |
524 gjc->fd = -1; | |
525 XML_ParserFree(gjc->parser); | |
526 gjc->parser = NULL; | |
2086 | 527 } |
528 | |
529 /* | |
2956 | 530 static int gjab_getfd(gjconn gjc) |
2086 | 531 { |
2956 | 532 if (gjc) |
533 return gjc->fd; | |
2086 | 534 else |
535 return -1; | |
536 } | |
537 | |
2956 | 538 static jid gjab_getjid(gjconn gjc) |
2086 | 539 { |
2956 | 540 if (gjc) |
541 return (gjc->user); | |
2086 | 542 else |
543 return NULL; | |
544 } | |
545 | |
2956 | 546 static char *gjab_getsid(gjconn gjc) |
2086 | 547 { |
2956 | 548 if (gjc) |
549 return (gjc->sid); | |
2086 | 550 else |
551 return NULL; | |
552 } | |
553 */ | |
554 | |
2956 | 555 static char *gjab_getid(gjconn gjc) |
2086 | 556 { |
2956 | 557 snprintf(gjc->idbuf, 8, "%d", gjc->id++); |
558 return &gjc->idbuf[0]; | |
2086 | 559 } |
560 | |
2956 | 561 static void gjab_send(gjconn gjc, xmlnode x) |
2086 | 562 { |
2956 | 563 if (gjc && gjc->state != JCONN_STATE_OFF) { |
2086 | 564 char *buf = xmlnode2str(x); |
565 if (buf) | |
3630 | 566 #ifndef _WIN32 |
2956 | 567 write(gjc->fd, buf, strlen(buf)); |
3630 | 568 #else |
569 send(gjc->fd, buf, strlen(buf), 0); | |
570 #endif | |
2086 | 571 debug_printf("gjab_send: %s\n", buf); |
572 } | |
573 } | |
574 | |
2956 | 575 static void gjab_send_raw(gjconn gjc, const char *str) |
2086 | 576 { |
2956 | 577 if (gjc && gjc->state != JCONN_STATE_OFF) { |
578 /* | |
579 * JFIXME: No error detection?!?! | |
580 */ | |
3630 | 581 #ifndef _WIN32 |
2956 | 582 if(write(gjc->fd, str, strlen(str)) < 0) { |
3630 | 583 #else |
584 if(send(gjc->fd, str, strlen(str), 0) < 0) { | |
585 #endif | |
2956 | 586 fprintf(stderr, "DBG: Problem sending. Error: %d\n", errno); |
587 fflush(stderr); | |
588 } | |
4450 | 589 /* printing keepalives to the debug window is really annoying */ |
590 if(strcmp(str, JABBER_KEEPALIVE_STRING)) | |
591 debug_printf("gjab_send_raw: %s\n", str); | |
2086 | 592 } |
593 } | |
594 | |
2956 | 595 static void gjab_reqroster(gjconn gjc) |
2086 | 596 { |
597 xmlnode x; | |
598 | |
599 x = jutil_iqnew(JPACKET__GET, NS_ROSTER); | |
2956 | 600 xmlnode_put_attrib(x, "id", gjab_getid(gjc)); |
601 | |
602 gjab_send(gjc, x); | |
2086 | 603 xmlnode_free(x); |
604 } | |
605 | |
2956 | 606 static void gjab_reqauth(gjconn gjc) |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
607 { |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
608 xmlnode x, y, z; |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
609 char *user; |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
610 |
2956 | 611 if (!gjc) |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
612 return; |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
613 |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
614 x = jutil_iqnew(JPACKET__GET, NS_AUTH); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
615 xmlnode_put_attrib(x, "id", IQID_AUTH); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
616 y = xmlnode_get_tag(x, "query"); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
617 |
2956 | 618 user = gjc->user->user; |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
619 |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
620 if (user) { |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
621 z = xmlnode_insert_tag(y, "username"); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
622 xmlnode_insert_cdata(z, user, -1); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
623 } |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
624 |
2956 | 625 gjab_send(gjc, x); |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
626 xmlnode_free(x); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
627 } |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
628 |
2956 | 629 static void gjab_auth(gjconn gjc) |
2086 | 630 { |
631 xmlnode x, y, z; | |
632 char *hash, *user; | |
633 | |
2956 | 634 if (!gjc) |
2086 | 635 return; |
636 | |
637 x = jutil_iqnew(JPACKET__SET, NS_AUTH); | |
638 xmlnode_put_attrib(x, "id", IQID_AUTH); | |
639 y = xmlnode_get_tag(x, "query"); | |
640 | |
2956 | 641 user = gjc->user->user; |
2086 | 642 |
643 if (user) { | |
644 z = xmlnode_insert_tag(y, "username"); | |
645 xmlnode_insert_cdata(z, user, -1); | |
646 } | |
647 | |
648 z = xmlnode_insert_tag(y, "resource"); | |
2956 | 649 xmlnode_insert_cdata(z, gjc->user->resource, -1); |
650 | |
651 if (gjc->sid) { | |
652 debug_printf("digest authentication (sid %s)\n", gjc->sid); | |
2086 | 653 z = xmlnode_insert_tag(y, "digest"); |
2956 | 654 hash = pmalloc(x->p, strlen(gjc->sid) + strlen(gjc->pass) + 1); |
655 strcpy(hash, gjc->sid); | |
656 strcat(hash, gjc->pass); | |
2086 | 657 hash = shahash(hash); |
658 xmlnode_insert_cdata(z, hash, 40); | |
659 } else { | |
660 z = xmlnode_insert_tag(y, "password"); | |
2956 | 661 xmlnode_insert_cdata(z, gjc->pass, -1); |
2086 | 662 } |
663 | |
2956 | 664 gjab_send(gjc, x); |
2086 | 665 xmlnode_free(x); |
666 | |
667 return; | |
668 } | |
669 | |
2956 | 670 static void gjab_recv(gjconn gjc) |
2086 | 671 { |
672 static char buf[4096]; | |
673 int len; | |
674 | |
2956 | 675 if (!gjc || gjc->state == JCONN_STATE_OFF) |
2086 | 676 return; |
3630 | 677 #ifndef _WIN32 |
3234 | 678 if ((len = read(gjc->fd, buf, sizeof(buf) - 1)) > 0) { |
3630 | 679 #else |
680 if ((len = recv(gjc->fd, buf, sizeof(buf) - 1, 0)) > 0) { | |
681 #endif | |
2956 | 682 struct jabber_data *jd = GJ_GC(gjc)->proto_data; |
2086 | 683 buf[len] = '\0'; |
684 debug_printf("input (len %d): %s\n", len, buf); | |
2956 | 685 XML_Parse(gjc->parser, buf, len, 0); |
2800
0ad63a625eec
[gaim-migrate @ 2813]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2791
diff
changeset
|
686 if (jd->die) |
2956 | 687 signoff(GJ_GC(gjc)); |
3105 | 688 } else if (len < 0 || errno != EAGAIN) { |
2086 | 689 STATE_EVT(JCONN_STATE_OFF) |
690 } | |
691 } | |
692 | |
693 static void startElement(void *userdata, const char *name, const char **attribs) | |
694 { | |
695 xmlnode x; | |
2956 | 696 gjconn gjc = (gjconn) userdata; |
697 | |
698 if (gjc->current) { | |
2086 | 699 /* Append the node to the current one */ |
2956 | 700 x = xmlnode_insert_tag(gjc->current, name); |
2086 | 701 xmlnode_put_expat_attribs(x, attribs); |
702 | |
2956 | 703 gjc->current = x; |
2086 | 704 } else { |
705 x = xmlnode_new_tag(name); | |
706 xmlnode_put_expat_attribs(x, attribs); | |
707 if (strcmp(name, "stream:stream") == 0) { | |
708 /* special case: name == stream:stream */ | |
709 /* id attrib of stream is stored for digest auth */ | |
2956 | 710 gjc->sid = g_strdup(xmlnode_get_attrib(x, "id")); |
2086 | 711 /* STATE_EVT(JCONN_STATE_AUTH) */ |
2635
8c75e59e4bdf
[gaim-migrate @ 2648]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2607
diff
changeset
|
712 xmlnode_free(x); |
2086 | 713 } else { |
2956 | 714 gjc->current = x; |
2086 | 715 } |
716 } | |
717 } | |
718 | |
719 static void endElement(void *userdata, const char *name) | |
720 { | |
2956 | 721 gjconn gjc = (gjconn) userdata; |
2086 | 722 xmlnode x; |
723 jpacket p; | |
724 | |
2956 | 725 if (gjc->current == NULL) { |
2086 | 726 /* we got </stream:stream> */ |
727 STATE_EVT(JCONN_STATE_OFF) | |
728 return; | |
729 } | |
730 | |
2956 | 731 x = xmlnode_get_parent(gjc->current); |
2086 | 732 |
733 if (!x) { | |
734 /* it is time to fire the event */ | |
2956 | 735 p = jpacket_new(gjc->current); |
736 | |
737 if (gjc->on_packet) | |
738 (gjc->on_packet) (gjc, p); | |
2086 | 739 else |
2956 | 740 xmlnode_free(gjc->current); |
2086 | 741 } |
742 | |
2956 | 743 gjc->current = x; |
2086 | 744 } |
745 | |
2090
b66aca8e8dce
[gaim-migrate @ 2100]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
746 static void jabber_callback(gpointer data, gint source, GaimInputCondition condition) |
2086 | 747 { |
748 struct gaim_connection *gc = (struct gaim_connection *)data; | |
749 struct jabber_data *jd = (struct jabber_data *)gc->proto_data; | |
750 | |
2956 | 751 gjab_recv(jd->gjc); |
2086 | 752 } |
753 | |
754 static void charData(void *userdata, const char *s, int slen) | |
755 { | |
2956 | 756 gjconn gjc = (gjconn) userdata; |
757 | |
758 if (gjc->current) | |
759 xmlnode_insert_cdata(gjc->current, s, slen); | |
2086 | 760 } |
761 | |
2090
b66aca8e8dce
[gaim-migrate @ 2100]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
762 static void gjab_connected(gpointer data, gint source, GaimInputCondition cond) |
2086 | 763 { |
764 xmlnode x; | |
765 char *t, *t2; | |
766 struct gaim_connection *gc = data; | |
767 struct jabber_data *jd; | |
2956 | 768 gjconn gjc; |
2086 | 769 |
770 if (!g_slist_find(connections, gc)) { | |
771 close(source); | |
772 return; | |
773 } | |
774 | |
775 jd = gc->proto_data; | |
2956 | 776 gjc = jd->gjc; |
777 | |
4366 | 778 gjc->fd = source; |
2300
d2686f757d6e
[gaim-migrate @ 2310]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2289
diff
changeset
|
779 |
2086 | 780 if (source == -1) { |
781 STATE_EVT(JCONN_STATE_OFF) | |
782 return; | |
783 } | |
784 | |
2956 | 785 gjc->state = JCONN_STATE_CONNECTED; |
2086 | 786 STATE_EVT(JCONN_STATE_CONNECTED) |
787 | |
788 /* start stream */ | |
2956 | 789 x = jutil_header(NS_CLIENT, gjc->user->server); |
2086 | 790 t = xmlnode2str(x); |
791 /* this is ugly, we can create the string here instead of jutil_header */ | |
792 /* what do you think about it? -madcat */ | |
793 t2 = strstr(t, "/>"); | |
794 *t2++ = '>'; | |
795 *t2 = '\0'; | |
2956 | 796 gjab_send_raw(gjc, "<?xml version='1.0'?>"); |
797 gjab_send_raw(gjc, t); | |
2086 | 798 xmlnode_free(x); |
799 | |
2956 | 800 gjc->state = JCONN_STATE_ON; |
2086 | 801 STATE_EVT(JCONN_STATE_ON); |
802 | |
2956 | 803 gc = GJ_GC(gjc); |
804 gc->inpa = gaim_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc); | |
2086 | 805 } |
806 | |
2956 | 807 static void gjab_start(gjconn gjc) |
2086 | 808 { |
4491 | 809 struct gaim_account *account; |
4366 | 810 int port, rc; |
4436 | 811 char *server; |
2086 | 812 |
2956 | 813 if (!gjc || gjc->state != JCONN_STATE_OFF) |
2086 | 814 return; |
815 | |
4491 | 816 account = GJ_GC(gjc)->account; |
817 port = account->proto_opt[USEROPT_PORT][0] ? atoi(account->proto_opt[USEROPT_PORT]) : DEFAULT_PORT; | |
818 server = account->proto_opt[USEROPT_CONN_SERVER][0] ? account->proto_opt[USEROPT_CONN_SERVER] : gjc->user->server; | |
4436 | 819 |
2086 | 820 |
2956 | 821 gjc->parser = XML_ParserCreate(NULL); |
822 XML_SetUserData(gjc->parser, (void *)gjc); | |
823 XML_SetElementHandler(gjc->parser, startElement, endElement); | |
824 XML_SetCharacterDataHandler(gjc->parser, charData); | |
825 | |
4634 | 826 rc = proxy_connect(account, server, port, gjab_connected, GJ_GC(gjc)); |
4491 | 827 if (!account->gc || (rc != 0)) { |
2086 | 828 STATE_EVT(JCONN_STATE_OFF) |
829 return; | |
830 } | |
831 } | |
832 | |
2956 | 833 /* |
834 * Find chat by chat group name | |
835 */ | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
836 static struct gaim_conversation *find_chat(struct gaim_connection *gc, char *name) |
2086 | 837 { |
838 GSList *bcs = gc->buddy_chats; | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
839 struct gaim_conversation *b = NULL; |
2086 | 840 char *chat = g_strdup(normalize(name)); |
841 | |
842 while (bcs) { | |
843 b = bcs->data; | |
844 if (!strcasecmp(normalize(b->name), chat)) | |
845 break; | |
846 b = NULL; | |
847 bcs = bcs->next; | |
848 } | |
849 | |
850 g_free(chat); | |
851 return b; | |
852 } | |
853 | |
2956 | 854 /* |
855 * Find chat by "chat id" | |
856 * | |
857 * Returns: 0 on success and jabber_chat pointer set | |
858 * or -EINVAL on error and jabber_chat pointer is | |
859 * undefined. | |
860 * | |
861 * TBD: Slogging through the buddy_chats list seems | |
862 * redundant since the chat i.d. is mirrored in the | |
863 * jabber_chat struct list. But that's the way it | |
864 * was, so that's the way I'm leaving it--for now. | |
865 */ | |
866 static int jabber_find_chat_by_convo_id(struct gaim_connection *gc, int id, struct jabber_chat **jc) | |
2086 | 867 { |
2956 | 868 GSList *bcs = gc->buddy_chats; |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
869 struct gaim_conversation *b = NULL; |
2956 | 870 struct jabber_data *jd = gc->proto_data; |
871 | |
872 *jc = NULL; | |
873 | |
874 while(bcs != NULL) { | |
875 b = bcs->data; | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
876 if (id == gaim_chat_get_id(GAIM_CHAT(b))) |
2956 | 877 break; |
878 bcs = bcs->next; | |
879 } | |
880 | |
881 if (bcs != NULL) { | |
882 bcs = jd->chats; | |
883 while (bcs != NULL) { | |
884 *jc = bcs->data; | |
885 if ((*jc)->state == JCS_ACTIVE && (*jc)->b == b) | |
886 break; | |
887 bcs = bcs->next; | |
888 } | |
889 } | |
890 | |
891 return(bcs == NULL? -EINVAL : 0); | |
892 } | |
893 | |
894 /* | |
895 * Find any chat | |
896 */ | |
897 static struct jabber_chat *find_any_chat(struct gaim_connection *gc, jid chat) | |
898 { | |
899 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; | |
2086 | 900 struct jabber_chat *jc = NULL; |
901 | |
2956 | 902 while (jcs) { |
903 jc = jcs->data; | |
3311 | 904 if (!jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER)) |
2086 | 905 break; |
906 jc = NULL; | |
2956 | 907 jcs = jcs->next; |
2086 | 908 } |
909 | |
910 return jc; | |
911 } | |
912 | |
2956 | 913 |
914 /* | |
915 * Find existing/active Jabber chat | |
916 */ | |
917 static struct jabber_chat *find_existing_chat(struct gaim_connection *gc, jid chat) | |
918 { | |
919 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; | |
920 struct jabber_chat *jc = NULL; | |
921 | |
922 while (jcs) { | |
923 jc = jcs->data; | |
3311 | 924 if (jc->state == JCS_ACTIVE && !jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER)) |
2956 | 925 break; |
926 jc = NULL; | |
927 jcs = jcs->next; | |
928 } | |
929 | |
930 return jc; | |
931 } | |
932 | |
933 /* | |
934 * Find pending chat | |
935 */ | |
2086 | 936 static struct jabber_chat *find_pending_chat(struct gaim_connection *gc, jid chat) |
937 { | |
2956 | 938 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; |
2086 | 939 struct jabber_chat *jc = NULL; |
940 | |
2956 | 941 while (jcs) { |
942 jc = jcs->data; | |
3311 | 943 if (jc->state == JCS_PENDING && !jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER)) |
2086 | 944 break; |
945 jc = NULL; | |
2956 | 946 jcs = jcs->next; |
2086 | 947 } |
948 | |
949 return jc; | |
950 } | |
951 | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
952 static gboolean find_chat_buddy(struct gaim_conversation *b, char *name) |
2086 | 953 { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
954 GList *m = gaim_chat_get_users(GAIM_CHAT(b)); |
2086 | 955 |
956 while (m) { | |
957 if (!strcmp(m->data, name)) | |
958 return TRUE; | |
959 m = m->next; | |
960 } | |
961 | |
962 return FALSE; | |
963 } | |
964 | |
2956 | 965 /* |
3236 | 966 * Remove a buddy from the (gaim) buddylist (if he's on it) |
967 */ | |
3466 | 968 static void jabber_remove_gaim_buddy(struct gaim_connection *gc, const char *buddyname) |
3236 | 969 { |
970 struct buddy *b; | |
971 | |
4687 | 972 if ((b = gaim_find_buddy(gc->account, buddyname)) != NULL) { |
4349 | 973 debug_printf("removing buddy [1]: %s\n", buddyname); |
4687 | 974 gaim_blist_remove_buddy(b); |
4349 | 975 gaim_blist_save(); |
3236 | 976 } |
977 } | |
978 | |
3466 | 979 static void jabber_change_passwd(struct gaim_connection *gc, const char *old, const char *new) |
3257 | 980 { |
981 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; | |
982 | |
983 if(strcmp(old, gjc->pass)) | |
984 { | |
3427 | 985 do_error_dialog(_("Unable to change password."), |
986 _("The current password you entered is incorrect. Your password has " | |
987 "not been changed."), GAIM_ERROR); | |
3257 | 988 } |
989 else if(!strcmp(old, new)) | |
990 { | |
3427 | 991 do_error_dialog(_("Unable to change password"), |
4059 | 992 _("The new password you entered is the same as your current password. " |
3427 | 993 "Your password remains the same."), GAIM_ERROR); |
3257 | 994 } |
995 else | |
996 { | |
997 xmlnode x, y, z; | |
998 char *id; | |
999 | |
1000 x = jutil_iqnew(JPACKET__SET, NS_REGISTER); | |
1001 xmlnode_put_attrib(x, "to", gjc->user->server); | |
1002 y = xmlnode_get_tag(x, "query"); | |
1003 z = xmlnode_insert_tag(y, "username"); | |
1004 xmlnode_insert_cdata(z, gjc->user->user, -1); | |
1005 z = xmlnode_insert_tag(y, "password"); | |
1006 xmlnode_insert_cdata(z, new, -1); | |
1007 | |
1008 id = gjab_getid(gjc); | |
1009 xmlnode_put_attrib(x, "id", id); | |
1010 | |
1011 free(gjc->pass); | |
1012 gjc->pass = strdup(new); | |
1013 | |
1014 g_hash_table_insert(gjc->queries, g_strdup(id), g_strdup("change_password")); | |
1015 | |
1016 gjab_send(gjc, x); | |
1017 xmlnode_free(x); | |
1018 } | |
1019 } | |
3311 | 1020 |
3340 | 1021 /* |
1022 * Return pointer to jabber_buddy_data if buddy found. Create if necessary. | |
1023 */ | |
3311 | 1024 static struct jabber_buddy_data* jabber_find_buddy(struct gaim_connection *gc, char *buddy) |
1025 { | |
1026 struct jabber_data *jd = gc->proto_data; | |
1027 gpointer val; | |
1028 char *realwho; | |
1029 | |
1030 if((realwho = get_realwho(jd->gjc, buddy, FALSE, NULL)) == NULL) | |
1031 return NULL; | |
1032 | |
1033 val = g_hash_table_lookup(jd->buddies, realwho); | |
1034 if(val) { | |
1035 g_free(realwho); | |
1036 return (struct jabber_buddy_data *)val; | |
1037 | |
1038 } else { | |
1039 struct jabber_buddy_data *jbd = g_new0(struct jabber_buddy_data, 1); | |
3340 | 1040 jbd->invisible = JABBER_NOT_INVIS; |
3311 | 1041 g_hash_table_insert(jd->buddies, g_strdup(realwho), jbd); |
1042 g_free(realwho); | |
1043 return jbd; | |
1044 } | |
1045 } | |
3770 | 1046 |
3236 | 1047 /* |
3311 | 1048 * find a resource by name, or if no name given, return the "default" resource |
3770 | 1049 * default being the highest priority one. |
3311 | 1050 */ |
1051 | |
1052 static jab_res_info jabber_find_resource(struct gaim_connection *gc, char *who) | |
1053 { | |
1054 GSList *resources; | |
1055 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, who); | |
1056 jab_res_info jri = NULL; | |
1057 char *res = strstr(who, "/"); | |
1058 | |
1059 if(res) | |
1060 res++; | |
1061 | |
1062 if(jbd) | |
1063 { | |
1064 resources = jbd->resources; | |
1065 while(resources) | |
1066 { | |
1067 if(!jri && !res) { | |
1068 jri = (jab_res_info) resources->data; | |
1069 } else if(!res) { /* we're looking for the default priority, so... */ | |
1070 if(((jab_res_info) resources->data)->priority >= jri->priority) | |
1071 jri = (jab_res_info) resources->data; | |
3337 | 1072 } else if(((jab_res_info)resources->data)->name) { |
3311 | 1073 if(!strcasecmp(((jab_res_info) resources->data)->name, res)) { |
1074 jri = (jab_res_info) resources->data; | |
1075 break; | |
1076 } | |
1077 } | |
1078 resources = resources->next; | |
1079 } | |
1080 } | |
1081 | |
1082 return jri; | |
1083 } | |
1084 | |
1085 /* | |
1086 * if the resource doesn't exist, create it. otherwise, just update the priority | |
2956 | 1087 */ |
3311 | 1088 static void jabber_track_resource(struct gaim_connection *gc, |
1089 char *buddy, | |
1090 char *res, | |
1091 int priority, | |
1092 int state) | |
1093 { | |
1094 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy); | |
1095 | |
3337 | 1096 if(jbd) { |
1097 char *who; | |
1098 jab_res_info jri; | |
1099 if(res) | |
1100 who = g_strdup_printf("%s/%s", buddy, res); | |
1101 else | |
1102 who = g_strdup(buddy); | |
1103 jri = jabber_find_resource(gc, who); | |
3311 | 1104 g_free(who); |
1105 if(!jri) { | |
1106 jri = g_new0(struct jabber_resource_info, 1); | |
1107 jri->name = g_strdup(res); | |
1108 jri->away_msg = NULL; | |
1109 jbd->resources = g_slist_append(jbd->resources, jri); | |
1110 } | |
1111 jri->priority = priority; | |
1112 jri->state = state; | |
1113 } | |
1114 } | |
1115 | |
1116 /* | |
1117 * remove the resource, if it exists | |
1118 */ | |
1119 static void jabber_remove_resource(struct gaim_connection *gc, char *buddy, char *res) | |
2956 | 1120 { |
3311 | 1121 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy); |
3337 | 1122 if(jbd) { |
1123 char *who; | |
1124 jab_res_info jri; | |
1125 if(res) | |
1126 who = g_strdup_printf("%s/%s", buddy, res); | |
1127 else | |
1128 who = g_strdup(buddy); | |
1129 jri = jabber_find_resource(gc, who); | |
3311 | 1130 g_free(who); |
1131 if(jri) { | |
3337 | 1132 if(jri->name) |
1133 g_free(jri->name); | |
3311 | 1134 if(jri->away_msg) |
1135 g_free(jri->away_msg); | |
1136 jbd->resources = g_slist_remove(jbd->resources, jri); | |
1137 g_free(jri); | |
1138 } | |
1139 } | |
1140 } | |
1141 | |
1142 /* | |
1143 * grab the away message for the default resource | |
1144 */ | |
1145 static char *jabber_lookup_away(gjconn gjc, char *name) | |
1146 { | |
1147 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name); | |
1148 | |
4745 | 1149 if(!jri) |
3311 | 1150 return _("Unknown"); |
1151 | |
1152 return jri->away_msg; | |
1153 } | |
4745 | 1154 static const char *jabber_get_state_string(int s) { |
1155 switch(s) { | |
1156 case UC_AWAY: | |
1157 return _("Away"); | |
1158 case UC_CHAT: | |
1159 return _("Chatty"); | |
1160 case UC_XA: | |
1161 return _("Extended Away"); | |
1162 case UC_DND: | |
1163 return _("Do Not Disturb"); | |
1164 default: | |
1165 return _("Available"); | |
1166 } | |
1167 } | |
3311 | 1168 |
1169 static void jabber_track_away(gjconn gjc, jpacket p, char *type) | |
1170 { | |
1171 jab_res_info jri = NULL; | |
1172 | |
3337 | 1173 if(!p || !p->from || !p->from->user) |
3311 | 1174 return; |
1175 | |
1176 jri = jabber_find_resource(GJ_GC(gjc), jid_full(p->from)); | |
1177 | |
1178 if(!jri) | |
1179 return; | |
3770 | 1180 |
3311 | 1181 if(jri->away_msg) |
1182 g_free(jri->away_msg); | |
1183 | |
4745 | 1184 jri->away_msg = g_strdup(xmlnode_get_tag_data(p->x, "status")); |
3311 | 1185 } |
1186 | |
1187 static void jabber_convo_closed(struct gaim_connection *gc, char *name) | |
1188 { | |
1189 jab_res_info jri = jabber_find_resource(gc, name); | |
1190 | |
1191 if(jri) { | |
1192 if(jri->thread_id) | |
1193 g_free(jri->thread_id); | |
1194 | |
1195 jri->thread_id = NULL; | |
2956 | 1196 } |
1197 } | |
1198 | |
3311 | 1199 static void jabber_track_convo_thread(gjconn gjc, char *name, char *thread_id) |
1200 { | |
1201 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name); | |
1202 | |
1203 if(jri) { | |
1204 if(jri->thread_id) | |
1205 g_free(jri->thread_id); | |
1206 | |
1207 jri->thread_id = g_strdup(thread_id); | |
1208 } | |
1209 } | |
1210 | |
1211 static char *jabber_get_convo_thread(gjconn gjc, char *name) | |
1212 { | |
1213 char *ct = NULL; | |
1214 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name); | |
1215 | |
1216 if(jri) { | |
1217 if(jri->thread_id) | |
1218 ct = g_strdup(jri->thread_id); | |
1219 } | |
3769 | 1220 if(!ct) { |
1221 char buf[1024]; | |
1222 snprintf(buf, sizeof(buf), "%s%d", name, (int)time(NULL)); | |
1223 ct = g_strdup(shahash(buf)); | |
1224 } | |
3311 | 1225 return ct; |
1226 } | |
1227 | |
1228 | |
3159 | 1229 static time_t iso8601_to_time(char *timestamp) |
1230 { | |
3229 | 1231 struct tm t; |
1232 time_t retval = 0; | |
1233 | |
3311 | 1234 if(sscanf(timestamp, "%04d%02d%02dT%02d:%02d:%02d", |
3229 | 1235 &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec)) |
1236 { | |
1237 t.tm_year -= 1900; | |
1238 t.tm_mon -= 1; | |
1239 t.tm_isdst = 0; | |
1240 retval = mktime(&t); | |
1241 # ifdef HAVE_TM_GMTOFF | |
1242 retval += t.tm_gmtoff; | |
1243 # else | |
1244 # ifdef HAVE_TIMEZONE | |
1245 tzset(); /* making sure */ | |
1246 retval -= timezone; | |
1247 # endif | |
1248 # endif | |
1249 } | |
1250 | |
1251 return retval; | |
3159 | 1252 } |
1253 | |
2956 | 1254 static void jabber_handlemessage(gjconn gjc, jpacket p) |
2086 | 1255 { |
3311 | 1256 xmlnode y, subj; |
3159 | 1257 time_t time_sent = time(NULL); |
3311 | 1258 gboolean typing = FALSE; |
2086 | 1259 |
1260 char *from = NULL, *msg = NULL, *type = NULL, *topic = NULL; | |
3311 | 1261 char *thread_id = NULL; |
1262 char *conference_room = NULL; | |
2086 | 1263 char m[BUF_LONG * 2]; |
1264 | |
1265 type = xmlnode_get_attrib(p->x, "type"); | |
3769 | 1266 |
3311 | 1267 if ((y = xmlnode_get_tag(p->x, "thread"))) |
1268 thread_id = xmlnode_get_data(y); | |
3769 | 1269 if(!thread_id) |
1270 thread_id = ""; | |
3311 | 1271 |
1272 y = xmlnode_get_firstchild(p->x); | |
1273 | |
1274 while(y) { | |
1275 if(NSCHECK(y, NS_DELAY)) { | |
1276 char *timestamp = xmlnode_get_attrib(y, "stamp"); | |
1277 time_sent = iso8601_to_time(timestamp); | |
1278 } else if(NSCHECK(y, "jabber:x:event")) { | |
1279 if(xmlnode_get_tag(y, "composing")) | |
1280 typing = TRUE; | |
1281 } else if(NSCHECK(y, "jabber:x:conference")) { | |
1282 conference_room = xmlnode_get_attrib(y, "jid"); | |
1283 } | |
1284 y = xmlnode_get_nextsibling(y); | |
3159 | 1285 } |
1286 | |
2086 | 1287 if (!type || !strcasecmp(type, "normal") || !strcasecmp(type, "chat")) { |
1288 | |
1289 from = jid_full(p->from); | |
1290 /* | |
1291 if ((y = xmlnode_get_tag(p->x, "html"))) { | |
1292 msg = xmlnode_get_data(y); | |
1293 } else | |
1294 */ | |
1295 if ((y = xmlnode_get_tag(p->x, "body"))) { | |
1296 msg = xmlnode_get_data(y); | |
1297 } | |
1298 | |
1299 if (!from) | |
1300 return; | |
1301 | |
3311 | 1302 if (conference_room) { |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
1303 GList *m = NULL; |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
1304 char **data; |
2086 | 1305 |
3311 | 1306 data = g_strsplit(conference_room, "@", 2); |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
1307 m = g_list_append(m, g_strdup(data[0])); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
1308 m = g_list_append(m, g_strdup(data[1])); |
2956 | 1309 m = g_list_append(m, g_strdup(gjc->user->user)); |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
1310 g_strfreev(data); |
2086 | 1311 |
3311 | 1312 serv_got_chat_invite(GJ_GC(gjc), conference_room, from, msg, m); |
2086 | 1313 } else if (msg) { /* whisper */ |
1314 struct jabber_chat *jc; | |
1315 g_snprintf(m, sizeof(m), "%s", msg); | |
2956 | 1316 if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b) |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1317 serv_got_chat_in(GJ_GC(gjc), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1318 gaim_chat_get_id(GAIM_CHAT(jc->b)), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1319 p->from->resource, 1, m, time_sent); |
2086 | 1320 else { |
2278
00a8b7bcef6c
[gaim-migrate @ 2288]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2232
diff
changeset
|
1321 int flags = 0; |
3769 | 1322 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), from); |
3311 | 1323 if(jri && typing) |
1324 jri->has_composing = TRUE; | |
2278
00a8b7bcef6c
[gaim-migrate @ 2288]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2232
diff
changeset
|
1325 if (xmlnode_get_tag(p->x, "gaim")) |
00a8b7bcef6c
[gaim-migrate @ 2288]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2232
diff
changeset
|
1326 flags = IM_FLAG_GAIMUSER; |
3769 | 1327 jabber_track_convo_thread(gjc, from, thread_id); |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1328 if (gaim_find_conversation(from)) |
3769 | 1329 serv_got_im(GJ_GC(gjc), from, m, flags, |
3311 | 1330 time_sent, -1); |
2086 | 1331 else { |
2956 | 1332 if(p->from->user) { |
3311 | 1333 from = g_strdup_printf("%s@%s", p->from->user, |
1334 p->from->server); | |
2956 | 1335 } else { |
3311 | 1336 /* server message? */ |
1337 from = g_strdup(p->from->server); | |
2956 | 1338 } |
3159 | 1339 serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1); |
2086 | 1340 g_free(from); |
1341 } | |
1342 } | |
3311 | 1343 } else { |
1344 /* a non-message message! */ | |
1345 from = g_strdup_printf("%s@%s", p->from->user, p->from->server); | |
1346 if(typing) | |
3768 | 1347 serv_got_typing(GJ_GC(gjc), from, 0, TYPING); |
3311 | 1348 else |
1349 serv_got_typing_stopped(GJ_GC(gjc), from); | |
1350 g_free(from); | |
2086 | 1351 } |
1352 | |
1353 } else if (!strcasecmp(type, "error")) { | |
1354 if ((y = xmlnode_get_tag(p->x, "error"))) { | |
1355 type = xmlnode_get_attrib(y, "code"); | |
1356 msg = xmlnode_get_data(y); | |
1357 } | |
1358 | |
1359 if (msg) { | |
3427 | 1360 from = g_strdup_printf(_("Jabber Error %s"), type ? type : ""); |
1361 do_error_dialog(from, msg, GAIM_ERROR); | |
2086 | 1362 g_free(from); |
1363 } | |
1364 } else if (!strcasecmp(type, "groupchat")) { | |
1365 struct jabber_chat *jc; | |
1366 static int i = 0; | |
1367 | |
1368 /* | |
1369 if ((y = xmlnode_get_tag(p->x, "html"))) { | |
1370 msg = xmlnode_get_data(y); | |
1371 } else | |
1372 */ | |
1373 if ((y = xmlnode_get_tag(p->x, "body"))) { | |
1374 msg = xmlnode_get_data(y); | |
1375 } | |
1376 | |
1377 if ((subj = xmlnode_get_tag(p->x, "subject"))) { | |
3770 | 1378 topic = xmlnode_get_data(subj); |
1379 } | |
2086 | 1380 |
2956 | 1381 jc = find_existing_chat(GJ_GC(gjc), p->from); |
2086 | 1382 if (!jc) { |
1383 /* we're not in this chat. are we supposed to be? */ | |
2956 | 1384 if ((jc = find_pending_chat(GJ_GC(gjc), p->from)) != NULL) { |
2086 | 1385 /* yes, we're supposed to be. so now we are. */ |
2956 | 1386 jc->b = serv_got_joined_chat(GJ_GC(gjc), i++, p->from->user); |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1387 jc->id = gaim_chat_get_id(GAIM_CHAT(jc->b)); |
2956 | 1388 jc->state = JCS_ACTIVE; |
2086 | 1389 } else { |
1390 /* no, we're not supposed to be. */ | |
1391 g_free(msg); | |
1392 return; | |
1393 } | |
1394 } | |
1395 if (p->from->resource) { | |
1396 if (!y) { | |
2956 | 1397 if (!find_chat_buddy(jc->b, p->from->resource)) { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1398 gaim_chat_add_user(GAIM_CHAT(jc->b), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1399 p->from->resource, NULL); |
2956 | 1400 } else if ((y = xmlnode_get_tag(p->x, "status"))) { |
3311 | 1401 jabber_track_away(gjc, p, NULL); |
2086 | 1402 } |
1403 } else if (jc->b && msg) { | |
1404 char buf[8192]; | |
1405 | |
1406 if (topic) { | |
1407 char tbuf[8192]; | |
1408 g_snprintf(tbuf, sizeof(tbuf), "%s", topic); | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1409 gaim_chat_set_topic(GAIM_CHAT(jc->b), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1410 p->from->resource, tbuf); |
2086 | 1411 } |
1412 | |
1413 g_snprintf(buf, sizeof(buf), "%s", msg); | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1414 serv_got_chat_in(GJ_GC(gjc), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1415 gaim_chat_get_id(GAIM_CHAT(jc->b)), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1416 p->from->resource, 0, buf, time_sent); |
2086 | 1417 } |
1418 } else { /* message from the server */ | |
3770 | 1419 if(jc->b && topic) { |
1420 char tbuf[8192]; | |
2086 | 1421 g_snprintf(tbuf, sizeof(tbuf), "%s", topic); |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1422 gaim_chat_set_topic(GAIM_CHAT(jc->b), "", tbuf); |
2086 | 1423 } |
1424 } | |
1425 | |
1426 } else { | |
1427 debug_printf("unhandled message %s\n", type); | |
1428 } | |
1429 } | |
3770 | 1430 |
2956 | 1431 static void jabber_handlepresence(gjconn gjc, jpacket p) |
2086 | 1432 { |
1433 char *to, *from, *type; | |
1434 struct buddy *b = NULL; | |
3311 | 1435 gaim_jid gjid; |
2086 | 1436 char *buddy; |
3194 | 1437 xmlnode y; |
2086 | 1438 char *show; |
2501
227cc42ffa6e
[gaim-migrate @ 2514]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2382
diff
changeset
|
1439 int state = 0; |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1440 struct gaim_conversation *cnv = NULL; |
2086 | 1441 struct jabber_chat *jc = NULL; |
3311 | 1442 int priority = 0; |
1443 struct jabber_buddy_data *jbd; | |
3770 | 1444 |
2086 | 1445 to = xmlnode_get_attrib(p->x, "to"); |
1446 from = xmlnode_get_attrib(p->x, "from"); | |
1447 type = xmlnode_get_attrib(p->x, "type"); | |
3770 | 1448 |
3311 | 1449 if((buddy = get_realwho(gjc, from, FALSE, &gjid)) == NULL) |
1450 return; | |
1451 | |
1452 if (gjid->user == NULL) { | |
1453 /* FIXME: transport */ | |
1454 g_free(buddy); | |
1455 gaim_jid_free(gjid); | |
1456 return; | |
1457 } | |
1458 | |
1459 jbd = jabber_find_buddy(GJ_GC(gjc), buddy); | |
1460 | |
1461 if(jbd->error_msg) { | |
1462 g_free(jbd->error_msg); | |
1463 jbd->error_msg = NULL; | |
1464 } | |
1465 | |
3259 | 1466 if(type && !strcasecmp(type, "error")) { |
1467 state = UC_ERROR; | |
3311 | 1468 if((y = xmlnode_get_tag(p->x, "error")) != NULL) { |
1469 jbd->error_msg = g_strdup_printf(_("Error %s: %s"), | |
1470 xmlnode_get_attrib(y, "code"), xmlnode_get_data(y)); | |
1471 } else { | |
1472 jbd->error_msg = g_strdup(_("Unknown Error in presence")); | |
1473 } | |
3259 | 1474 } else { |
1475 if ((y = xmlnode_get_tag(p->x, "show"))) { | |
1476 show = xmlnode_get_data(y); | |
1477 if (!show) { | |
1478 state = 0; | |
1479 } else if (!strcasecmp(show, "away")) { | |
1480 state = UC_AWAY; | |
1481 } else if (!strcasecmp(show, "chat")) { | |
1482 state = UC_CHAT; | |
1483 } else if (!strcasecmp(show, "xa")) { | |
1484 state = UC_XA; | |
1485 } else if (!strcasecmp(show, "dnd")) { | |
1486 state = UC_DND; | |
1487 } | |
1488 } else { | |
2501
227cc42ffa6e
[gaim-migrate @ 2514]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2382
diff
changeset
|
1489 state = 0; |
2086 | 1490 } |
1491 } | |
1492 | |
3311 | 1493 if ((y = xmlnode_get_tag(p->x, "priority"))) |
3770 | 1494 priority = atoi(xmlnode_get_data(y)); |
2086 | 1495 |
1496 /* um. we're going to check if it's a chat. if it isn't, and there are pending | |
2956 | 1497 * chats, create the chat. if there aren't pending chats and we don't have the |
1498 * buddy on our list, simply bail out. */ | |
3311 | 1499 if ((cnv = find_chat(GJ_GC(gjc), gjid->user)) == NULL) { |
2086 | 1500 static int i = 0x70; |
3311 | 1501 if ((jc = find_pending_chat(GJ_GC(gjc), gjid)) != NULL) { |
1502 jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, gjid->user); | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1503 jc->id = gaim_chat_get_id(GAIM_CHAT(jc->b)); |
2956 | 1504 jc->state = JCS_ACTIVE; |
4687 | 1505 } else if ((b = gaim_find_buddy(GJ_GC(gjc)->account, buddy)) == NULL) { |
2956 | 1506 g_free(buddy); |
3311 | 1507 gaim_jid_free(gjid); |
2956 | 1508 return; |
2086 | 1509 } |
1510 } | |
1511 | |
4732 | 1512 if (state == UC_ERROR || (type && (strcasecmp(type, "unavailable") == 0))) |
3311 | 1513 jabber_remove_resource(GJ_GC(gjc), buddy, gjid->resource); |
1514 else { | |
1515 jabber_track_resource(GJ_GC(gjc), buddy, gjid->resource, priority, state); | |
1516 | |
1517 /* keep track of away msg somewhat the same as the yahoo plugin */ | |
1518 jabber_track_away(gjc, p, type); | |
1519 } | |
3770 | 1520 |
3311 | 1521 |
2086 | 1522 if (!cnv) { |
3311 | 1523 /* this is where we handle presence information for "regular" buddies */ |
1524 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), buddy); | |
1525 if(jri) { | |
4732 | 1526 serv_got_update(GJ_GC(gjc), buddy, 1, 0, b->signon, b->idle, jri->state); |
3311 | 1527 } else |
4732 | 1528 serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0); |
3311 | 1529 |
2086 | 1530 } else { |
3311 | 1531 if (gjid->resource) { |
3259 | 1532 if (type && (!strcasecmp(type, "unavailable"))) { |
2086 | 1533 struct jabber_data *jd; |
3311 | 1534 if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), gjid))) { |
2086 | 1535 g_free(buddy); |
3311 | 1536 gaim_jid_free(gjid); |
2086 | 1537 return; |
1538 } | |
1539 jd = jc->gc->proto_data; | |
2956 | 1540 /* if it's not ourselves...*/ |
3311 | 1541 if (strcmp(gjid->resource, jc->gjid->resource) && jc->b) { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1542 gaim_chat_remove_user(GAIM_CHAT(jc->b), gjid->resource, |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1543 NULL); |
2086 | 1544 g_free(buddy); |
3311 | 1545 gaim_jid_free(gjid); |
2086 | 1546 return; |
1547 } | |
2956 | 1548 |
1549 jc->state = JCS_CLOSED; | |
1550 serv_got_chat_left(GJ_GC(gjc), jc->id); | |
1551 /* | |
1552 * TBD: put back some day? | |
1553 jd->chats = g_slist_remove(jd->chats, jc); | |
1554 g_free(jc); | |
1555 */ | |
1556 } else { | |
3311 | 1557 if ((!jc && !(jc = find_existing_chat(GJ_GC(gjc), gjid))) || !jc->b) { |
2956 | 1558 g_free(buddy); |
3311 | 1559 gaim_jid_free(gjid); |
2956 | 1560 return; |
1561 } | |
3311 | 1562 if (!find_chat_buddy(jc->b, gjid->resource)) { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1563 gaim_chat_add_user(GAIM_CHAT(jc->b), gjid->resource, NULL); |
2086 | 1564 } |
1565 } | |
1566 } | |
1567 } | |
1568 | |
1569 g_free(buddy); | |
3311 | 1570 gaim_jid_free(gjid); |
2086 | 1571 |
1572 return; | |
1573 } | |
1574 | |
3229 | 1575 /* |
1576 * Used only by Jabber accept/deny add stuff just below | |
1577 */ | |
1578 struct jabber_add_permit { | |
4249 | 1579 struct gaim_connection *gc; |
3229 | 1580 gchar *user; |
1581 }; | |
1582 | |
1583 /* | |
1584 * Common part for Jabber accept/deny adds | |
1585 * | |
1586 * "type" says whether we'll permit/deny the subscribe request | |
1587 */ | |
1588 static void jabber_accept_deny_add(struct jabber_add_permit *jap, const char *type) | |
1589 { | |
1590 xmlnode g = xmlnode_new_tag("presence"); | |
1591 | |
1592 xmlnode_put_attrib(g, "to", jap->user); | |
1593 xmlnode_put_attrib(g, "type", type); | |
4249 | 1594 gjab_send(GC_GJ(jap->gc), g); |
3229 | 1595 |
1596 xmlnode_free(g); | |
1597 } | |
1598 | |
1599 /* | |
1600 * Callback from "accept" in do_ask_dialog() invoked by jabber_handles10n() | |
1601 */ | |
3730 | 1602 static void jabber_accept_add(struct jabber_add_permit *jap) |
3229 | 1603 { |
4249 | 1604 if(g_slist_find(connections, jap->gc)) { |
1605 jabber_accept_deny_add(jap, "subscribed"); | |
1606 /* | |
1607 * If we don't already have the buddy on *our* buddylist, | |
1608 * ask if we want him or her added. | |
1609 */ | |
4687 | 1610 if(gaim_find_buddy(jap->gc->account, jap->user) == NULL) { |
4249 | 1611 show_got_added(jap->gc, NULL, jap->user, NULL, NULL); |
1612 } | |
3229 | 1613 } |
4249 | 1614 |
3229 | 1615 g_free(jap->user); |
1616 g_free(jap); | |
1617 } | |
1618 | |
1619 /* | |
1620 * Callback from "deny/cancel" in do_ask_dialog() invoked by jabber_handles10n() | |
1621 */ | |
3730 | 1622 static void jabber_deny_add(struct jabber_add_permit *jap) |
3229 | 1623 { |
4249 | 1624 if(g_slist_find(connections, jap->gc)) { |
1625 jabber_accept_deny_add(jap, "unsubscribed"); | |
1626 } | |
1627 | |
3229 | 1628 g_free(jap->user); |
1629 g_free(jap); | |
1630 } | |
1631 | |
1632 /* | |
1633 * Handle subscription requests | |
1634 */ | |
2956 | 1635 static void jabber_handles10n(gjconn gjc, jpacket p) |
2086 | 1636 { |
1637 xmlnode g; | |
1638 char *Jid = xmlnode_get_attrib(p->x, "from"); | |
3136 | 1639 char *type = xmlnode_get_attrib(p->x, "type"); |
2086 | 1640 |
1641 g = xmlnode_new_tag("presence"); | |
1642 xmlnode_put_attrib(g, "to", Jid); | |
3229 | 1643 |
1644 if (!strcmp(type, "subscribe")) { | |
1645 /* | |
1646 * A "subscribe to us" request was received - put up the approval dialog | |
1647 */ | |
1648 struct jabber_add_permit *jap = g_new0(struct jabber_add_permit, 1); | |
1649 gchar *msg = g_strdup_printf(_("The user %s wants to add you to their buddy list."), | |
1650 Jid); | |
1651 | |
4249 | 1652 jap->gc = GJ_GC(gjc); |
3229 | 1653 jap->user = g_strdup(Jid); |
4249 | 1654 do_ask_dialog(msg, NULL, jap, _("Authorize"), jabber_accept_add, _("Deny"), jabber_deny_add, my_protocol->plug ? my_protocol->plug->handle : NULL, FALSE); |
3229 | 1655 |
1656 g_free(msg); | |
1657 xmlnode_free(g); /* Never needed it here anyway */ | |
1658 return; | |
1659 | |
1660 } else if (!strcmp(type, "unsubscribe")) { | |
1661 /* | |
1662 * An "unsubscribe to us" was received - simply "approve" it | |
1663 */ | |
2086 | 1664 xmlnode_put_attrib(g, "type", "unsubscribed"); |
3229 | 1665 } else { |
1666 /* | |
1667 * Did we attempt to subscribe to somebody and they do not exist? | |
1668 */ | |
3136 | 1669 if (!strcmp(type, "unsubscribed")) { |
1670 xmlnode y; | |
1671 char *status; | |
1672 if((y = xmlnode_get_tag(p->x, "status")) && (status = xmlnode_get_data(y)) && | |
1673 !strcmp(status, "Not Found")) { | |
3427 | 1674 char *msg = g_strdup_printf(_("The Jabber user %s does not exist and was therefore " |
1675 "not added to your roster."), | |
1676 xmlnode_get_attrib(p->x, "from")); | |
1677 do_error_dialog(_("No such user."), msg, GAIM_ERROR ); | |
3136 | 1678 g_free(msg); |
1679 } | |
1680 } | |
1681 | |
2956 | 1682 xmlnode_free(g); |
2086 | 1683 return; |
2956 | 1684 } |
1685 | |
1686 gjab_send(gjc, g); | |
1687 xmlnode_free(g); | |
2086 | 1688 } |
1689 | |
2956 | 1690 /* |
1691 * Pending subscription to a buddy? | |
1692 */ | |
1693 #define BUD_SUB_TO_PEND(sub, ask) ((!strcasecmp((sub), "none") || !strcasecmp((sub), "from")) && \ | |
3770 | 1694 (ask) != NULL && !strcasecmp((ask), "subscribe")) |
2956 | 1695 |
1696 /* | |
1697 * Subscribed to a buddy? | |
1698 */ | |
1699 #define BUD_SUBD_TO(sub, ask) ((!strcasecmp((sub), "to") || !strcasecmp((sub), "both")) && \ | |
1700 ((ask) == NULL || !strcasecmp((ask), "subscribe"))) | |
1701 | |
1702 /* | |
1703 * Pending unsubscription to a buddy? | |
1704 */ | |
1705 #define BUD_USUB_TO_PEND(sub, ask) ((!strcasecmp((sub), "to") || !strcasecmp((sub), "both")) && \ | |
1706 (ask) != NULL && !strcasecmp((ask), "unsubscribe")) | |
1707 | |
1708 /* | |
1709 * Unsubscribed to a buddy? | |
1710 */ | |
1711 #define BUD_USUBD_TO(sub, ask) ((!strcasecmp((sub), "none") || !strcasecmp((sub), "from")) && \ | |
1712 ((ask) == NULL || !strcasecmp((ask), "unsubscribe"))) | |
1713 | |
1714 /* | |
1715 * If a buddy is added or removed from the roster on another resource | |
1716 * jabber_handlebuddy is called | |
1717 * | |
1718 * Called with roster item node. | |
1719 */ | |
1720 static void jabber_handlebuddy(gjconn gjc, xmlnode x) | |
1721 { | |
1722 xmlnode g; | |
3311 | 1723 char *who, *name, *sub, *ask; |
1724 gaim_jid gjid; | |
2956 | 1725 struct buddy *b = NULL; |
4927 | 1726 struct jabber_buddy_data *jbd = NULL; |
3136 | 1727 char *buddyname, *groupname = NULL; |
2956 | 1728 |
3311 | 1729 who = xmlnode_get_attrib(x, "jid"); |
2956 | 1730 name = xmlnode_get_attrib(x, "name"); |
1731 sub = xmlnode_get_attrib(x, "subscription"); | |
1732 ask = xmlnode_get_attrib(x, "ask"); | |
3311 | 1733 |
1734 if((buddyname = get_realwho(gjc, who, FALSE, &gjid)) == NULL) | |
1735 return; | |
2956 | 1736 |
4705 | 1737 |
2956 | 1738 /* JFIXME: jabber_handleroster() had a "FIXME: transport" at this |
1739 * equivilent point. So... | |
1740 * | |
3311 | 1741 * We haven't done anything interesting to this point, so we'll |
1742 * violate Good Coding Structure here by simply bailing out. | |
2956 | 1743 */ |
3311 | 1744 if(!gjid->user) { |
1745 g_free(buddyname); | |
1746 gaim_jid_free(gjid); | |
2956 | 1747 return; |
1748 } | |
3311 | 1749 gaim_jid_free(gjid); |
2956 | 1750 |
3236 | 1751 if((g = xmlnode_get_tag(x, "group")) != NULL) { |
3136 | 1752 groupname = xmlnode_get_data(g); |
2956 | 1753 } |
1754 | |
3059 | 1755 /* |
3136 | 1756 * Add or remove a buddy? Change buddy's alias or group? |
3059 | 1757 */ |
2956 | 1758 if (BUD_SUB_TO_PEND(sub, ask) || BUD_SUBD_TO(sub, ask)) { |
4687 | 1759 if ((b = gaim_find_buddy(GJ_GC(gjc)->account, buddyname)) == NULL) { |
4932 | 1760 struct group *g; |
4927 | 1761 b = gaim_buddy_new(GJ_GC(gjc)->account, buddyname, name); |
4687 | 1762 if (groupname) { |
4775 | 1763 if (!(g = gaim_find_group(groupname))) { |
4687 | 1764 g = gaim_group_new(groupname); |
4775 | 1765 gaim_blist_add_group(g, NULL); |
1766 } | |
1767 } else { | |
4687 | 1768 g = gaim_group_new(_("Buddies")); |
4775 | 1769 gaim_blist_add_group(g, NULL); |
1770 } | |
2956 | 1771 debug_printf("adding buddy [4]: %s\n", buddyname); |
4687 | 1772 gaim_blist_add_buddy(b, g, NULL); |
4349 | 1773 gaim_blist_save(); |
3136 | 1774 } else { |
4687 | 1775 struct group *c_grp = gaim_find_buddys_group(b); |
3136 | 1776 |
3770 | 1777 /* |
3136 | 1778 * If the buddy's in a new group or his/her alias is changed... |
1779 */ | |
1780 if(groupname && c_grp && strcmp(c_grp->name, groupname)) { | |
1781 int present = b->present; /* save presence state */ | |
1782 int uc = b->uc; /* and away state (?) */ | |
3150 | 1783 int idle = b->idle; |
1784 int signon = b->signon; | |
3136 | 1785 |
1786 /* | |
1787 * seems rude, but it seems to be the only way... | |
1788 */ | |
4687 | 1789 gaim_blist_remove_buddy(b); |
4705 | 1790 b = gaim_buddy_new(GJ_GC(gjc)->account, buddyname, name); |
4687 | 1791 gaim_blist_add_buddy(b, gaim_find_group(groupname), NULL); |
4349 | 1792 gaim_blist_save(); |
3136 | 1793 if(present) { |
3311 | 1794 serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle, |
4732 | 1795 uc); |
3136 | 1796 } |
4227 | 1797 } else if(name != NULL && strcmp(b->alias, name)) { |
4705 | 1798 g_free(b->alias); |
1799 b->alias = g_strdup(name); | |
4687 | 1800 gaim_blist_rename_buddy(b, buddyname); |
4349 | 1801 gaim_blist_save(); |
3136 | 1802 } |
2956 | 1803 } |
1804 } else if (BUD_USUB_TO_PEND(sub, ask) || BUD_USUBD_TO(sub, ask) || !strcasecmp(sub, "remove")) { | |
3236 | 1805 jabber_remove_gaim_buddy(GJ_GC(gjc), buddyname); |
2956 | 1806 } |
4927 | 1807 if(b && (jbd = jabber_find_buddy(b->account->gc, buddyname)) != NULL) { |
1808 jbd->subscription = JABBER_SUB_NONE; | |
1809 if(!strcasecmp(sub, "to")) | |
1810 jbd->subscription |= JABBER_SUB_TO; | |
1811 else if(!strcasecmp(sub, "from")) | |
1812 jbd->subscription |= JABBER_SUB_FROM; | |
1813 else if(!strcasecmp(sub, "both")) | |
1814 jbd->subscription |= JABBER_SUB_BOTH; | |
1815 | |
1816 if(ask && !strcasecmp(ask, "subscribe")) | |
1817 jbd->subscription |= JABBER_SUB_PENDING; | |
1818 } | |
3328 | 1819 |
2956 | 1820 g_free(buddyname); |
1821 | |
1822 } | |
1823 | |
1824 static void jabber_handleroster(gjconn gjc, xmlnode querynode) | |
2086 | 1825 { |
1826 xmlnode x; | |
1827 | |
1828 x = xmlnode_get_firstchild(querynode); | |
1829 while (x) { | |
2956 | 1830 jabber_handlebuddy(gjc, x); |
2086 | 1831 x = xmlnode_get_nextsibling(x); |
1832 } | |
1833 | |
1834 x = jutil_presnew(0, NULL, "Online"); | |
2956 | 1835 gjab_send(gjc, x); |
2086 | 1836 xmlnode_free(x); |
1837 } | |
1838 | |
2956 | 1839 static void jabber_handleauthresp(gjconn gjc, jpacket p) |
2086 | 1840 { |
1841 if (jpacket_subtype(p) == JPACKET__RESULT) { | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1842 if (xmlnode_has_children(p->x)) { |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1843 xmlnode query = xmlnode_get_tag(p->x, "query"); |
2975 | 1844 set_login_progress(GJ_GC(gjc), 4, _("Authenticating")); |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1845 if (!xmlnode_get_tag(query, "digest")) { |
2956 | 1846 g_free(gjc->sid); |
1847 gjc->sid = NULL; | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1848 } |
2956 | 1849 gjab_auth(gjc); |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1850 } else { |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1851 debug_printf("auth success\n"); |
2086 | 1852 |
2956 | 1853 account_online(GJ_GC(gjc)); |
1854 serv_finish_login(GJ_GC(gjc)); | |
1855 | |
1856 ((struct jabber_data *)GJ_GC(gjc)->proto_data)->did_import = TRUE; | |
1857 | |
1858 gjab_reqroster(gjc); | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1859 } |
2086 | 1860 } else { |
1861 xmlnode xerr; | |
1862 char *errmsg = NULL; | |
1863 int errcode = 0; | |
2956 | 1864 struct jabber_data *jd = GJ_GC(gjc)->proto_data; |
2086 | 1865 |
1866 debug_printf("auth failed\n"); | |
1867 xerr = xmlnode_get_tag(p->x, "error"); | |
1868 if (xerr) { | |
1869 char msg[BUF_LONG]; | |
1870 errmsg = xmlnode_get_data(xerr); | |
1871 if (xmlnode_get_attrib(xerr, "code")) { | |
1872 errcode = atoi(xmlnode_get_attrib(xerr, "code")); | |
1873 g_snprintf(msg, sizeof(msg), "Error %d: %s", errcode, errmsg); | |
1874 } else | |
1875 g_snprintf(msg, sizeof(msg), "%s", errmsg); | |
2956 | 1876 hide_login_progress(GJ_GC(gjc), msg); |
2086 | 1877 } else { |
2975 | 1878 hide_login_progress(GJ_GC(gjc), _("Unknown login error")); |
2086 | 1879 } |
1880 | |
2800
0ad63a625eec
[gaim-migrate @ 2813]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2791
diff
changeset
|
1881 jd->die = TRUE; |
2086 | 1882 } |
1883 } | |
1884 | |
2956 | 1885 static void jabber_handleversion(gjconn gjc, xmlnode iqnode) { |
2086 | 1886 xmlnode querynode, x; |
1887 char *id, *from; | |
1888 char os[1024]; | |
1889 struct utsname osinfo; | |
1890 | |
1891 uname(&osinfo); | |
1892 g_snprintf(os, sizeof os, "%s %s %s", osinfo.sysname, osinfo.release, osinfo.machine); | |
1893 | |
1894 id = xmlnode_get_attrib(iqnode, "id"); | |
1895 from = xmlnode_get_attrib(iqnode, "from"); | |
1896 | |
1897 x = jutil_iqnew(JPACKET__RESULT, NS_VERSION); | |
1898 | |
1899 xmlnode_put_attrib(x, "to", from); | |
1900 xmlnode_put_attrib(x, "id", id); | |
1901 querynode = xmlnode_get_tag(x, "query"); | |
1902 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "name"), PACKAGE, -1); | |
1903 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "version"), VERSION, -1); | |
1904 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "os"), os, -1); | |
1905 | |
2956 | 1906 gjab_send(gjc, x); |
2086 | 1907 |
1908 xmlnode_free(x); | |
1909 } | |
1910 | |
2956 | 1911 static void jabber_handletime(gjconn gjc, xmlnode iqnode) { |
2086 | 1912 xmlnode querynode, x; |
1913 char *id, *from; | |
3770 | 1914 time_t now_t; |
2086 | 1915 struct tm *now; |
1916 char buf[1024]; | |
1917 | |
1918 time(&now_t); | |
1919 now = localtime(&now_t); | |
1920 | |
1921 id = xmlnode_get_attrib(iqnode, "id"); | |
1922 from = xmlnode_get_attrib(iqnode, "from"); | |
1923 | |
1924 x = jutil_iqnew(JPACKET__RESULT, NS_TIME); | |
1925 | |
1926 xmlnode_put_attrib(x, "to", from); | |
1927 xmlnode_put_attrib(x, "id", id); | |
1928 querynode = xmlnode_get_tag(x, "query"); | |
1929 | |
1930 strftime(buf, 1024, "%Y%m%dT%T", now); | |
1931 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "utc"), buf, -1); | |
1932 strftime(buf, 1024, "%Z", now); | |
1933 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "tz"), buf, -1); | |
1934 strftime(buf, 1024, "%d %b %Y %T", now); | |
1935 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "display"), buf, -1); | |
3770 | 1936 |
2956 | 1937 gjab_send(gjc, x); |
2086 | 1938 |
1939 xmlnode_free(x); | |
1940 } | |
1941 | |
4538 | 1942 struct jabber_xfer_data { |
3630 | 1943 struct g_url *url; |
1944 GString *headers; | |
1945 gboolean newline; | |
4538 | 1946 |
1947 char *iq_id; | |
1948 | |
1949 struct jabber_data *jd; | |
3630 | 1950 }; |
1951 | |
4538 | 1952 static void jabber_xfer_init(struct gaim_xfer *xfer) |
1953 { | |
1954 struct jabber_xfer_data *data = xfer->data; | |
1955 gaim_xfer_start(xfer, -1, data->url->address, data->url->port); | |
1956 } | |
1957 | |
1958 static void jabber_xfer_free(struct gaim_xfer *xfer) | |
1959 { | |
1960 struct jabber_xfer_data *data = xfer->data; | |
1961 data->jd->file_transfers = g_slist_remove(data->jd->file_transfers, xfer); | |
1962 | |
1963 g_string_free(data->headers, TRUE); | |
1964 g_free(data->url); | |
1965 g_free(data->iq_id); | |
1966 g_free(data); | |
1967 | |
1968 xfer->data = NULL; | |
3630 | 1969 } |
1970 | |
4538 | 1971 static void jabber_xfer_end(struct gaim_xfer *xfer) |
1972 { | |
1973 struct jabber_xfer_data *data = xfer->data; | |
1974 xmlnode x; | |
1975 | |
1976 x = xmlnode_new_tag("iq"); | |
1977 xmlnode_put_attrib(x, "type", "result"); | |
1978 xmlnode_put_attrib(x, "to", xfer->who); | |
1979 xmlnode_put_attrib(x, "id", data->iq_id); | |
1980 | |
1981 gjab_send(data->jd->gjc, x); | |
1982 | |
1983 xmlnode_free(x); | |
1984 | |
1985 jabber_xfer_free(xfer); | |
1986 } | |
1987 | |
1988 static void jabber_xfer_start(struct gaim_xfer *xfer) | |
1989 { | |
1990 struct jabber_xfer_data *data = xfer->data; | |
1991 char *buf = g_strdup_printf("GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", | |
1992 data->url->page, data->url->address); | |
1993 write(xfer->fd, buf, strlen(buf)); | |
1994 g_free(buf); | |
1995 } | |
1996 | |
1997 static size_t jabber_xfer_read(char **buffer, struct gaim_xfer *xfer) { | |
1998 struct jabber_xfer_data *data = xfer->data; | |
3630 | 1999 char test; |
4538 | 2000 size_t size; |
2001 | |
2002 if(read(xfer->fd, &test, sizeof(test)) > 0) { | |
2003 data->headers = g_string_append_c(data->headers, test); | |
2004 if(test == '\r') | |
2005 return 0; | |
2006 if(test == '\n') { | |
2007 if(data->newline) { | |
2008 gchar *lenstr = strstr(data->headers->str, "Content-Length: "); | |
2009 if(lenstr) { | |
2010 sscanf(lenstr, "Content-Length: %d", &size); | |
2011 gaim_xfer_set_size(xfer, size); | |
2012 } | |
2013 gaim_xfer_set_read_fnc(xfer, NULL); | |
2014 return 0; | |
2015 } else | |
2016 data->newline = TRUE; | |
2017 return 0; | |
3630 | 2018 } |
4538 | 2019 data->newline = FALSE; |
2020 return 0; | |
3630 | 2021 } |
4538 | 2022 return 0; |
3630 | 2023 } |
2024 | |
4675
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2025 static void jabber_xfer_cancel_send(struct gaim_xfer *xfer) { |
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2026 } |
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2027 |
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2028 static void jabber_xfer_cancel_recv(struct gaim_xfer *xfer) { |
4538 | 2029 struct jabber_xfer_data *data = xfer->data; |
3630 | 2030 xmlnode x,y; |
2031 | |
2032 x = xmlnode_new_tag("iq"); | |
2033 xmlnode_put_attrib(x, "type", "error"); | |
4538 | 2034 xmlnode_put_attrib(x, "to", xfer->who); |
2035 xmlnode_put_attrib(x, "id", data->iq_id); | |
3630 | 2036 y = xmlnode_insert_tag(x, "error"); |
2037 /* FIXME: need to handle other kinds of errors here */ | |
2038 xmlnode_put_attrib(y, "code", "406"); | |
2039 xmlnode_insert_cdata(y, "File Transfer Refused", -1); | |
2040 | |
4538 | 2041 gjab_send(data->jd->gjc, x); |
3630 | 2042 |
2043 xmlnode_free(x); | |
2044 | |
4538 | 2045 jabber_xfer_free(xfer); |
3630 | 2046 } |
2047 | |
2048 static void jabber_handleoob(gjconn gjc, xmlnode iqnode) { | |
4538 | 2049 struct jabber_xfer_data *xfer_data; |
3630 | 2050 struct jabber_data *jd = GJ_GC(gjc)->proto_data; |
4675
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2051 struct gaim_xfer *xfer; |
3630 | 2052 char *msg = NULL; |
4538 | 2053 char *filename; |
3630 | 2054 xmlnode querynode = xmlnode_get_tag(iqnode, "query"); |
2055 xmlnode urlnode,descnode; | |
2056 | |
2057 if(!querynode) | |
2058 return; | |
2059 urlnode = xmlnode_get_tag(querynode, "url"); | |
2060 if(!urlnode) | |
2061 return; | |
2062 descnode = xmlnode_get_tag(querynode, "desc"); | |
2063 if(descnode) | |
2064 msg = xmlnode_get_data(descnode); | |
2065 | |
4538 | 2066 xfer_data = g_new0(struct jabber_xfer_data, 1); |
2067 xfer_data->url = parse_url(xmlnode_get_data(urlnode)); | |
2068 xfer_data->jd = jd; | |
2069 xfer_data->headers = g_string_new(""); | |
2070 xfer_data->iq_id = g_strdup(xmlnode_get_attrib(iqnode, "id")); | |
2071 | |
2072 xfer = gaim_xfer_new(GJ_GC(gjc)->account, GAIM_XFER_RECEIVE, | |
2073 xmlnode_get_attrib(iqnode, "from")); | |
2074 xfer->data = xfer_data; | |
2075 | |
2076 filename = g_strdup(g_strrstr(xfer_data->url->page, "/")); | |
2077 if(!filename) | |
2078 filename = g_strdup(xfer_data->url->page); | |
2079 | |
2080 gaim_xfer_set_filename(xfer, filename); | |
2081 | |
2082 g_free(filename); | |
2083 | |
2084 gaim_xfer_set_init_fnc(xfer, jabber_xfer_init); | |
2085 gaim_xfer_set_end_fnc(xfer, jabber_xfer_end); | |
4675
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2086 gaim_xfer_set_cancel_send_fnc(xfer, jabber_xfer_cancel_send); |
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2087 gaim_xfer_set_cancel_recv_fnc(xfer, jabber_xfer_cancel_recv); |
4538 | 2088 gaim_xfer_set_read_fnc(xfer, jabber_xfer_read); |
2089 gaim_xfer_set_start_fnc(xfer, jabber_xfer_start); | |
2090 | |
2091 jd->file_transfers = g_slist_append(jd->file_transfers, xfer); | |
2092 | |
2093 gaim_xfer_request(xfer); | |
3630 | 2094 } |
2095 | |
2956 | 2096 static void jabber_handlelast(gjconn gjc, xmlnode iqnode) { |
3630 | 2097 xmlnode x, querytag; |
2086 | 2098 char *id, *from; |
2956 | 2099 struct jabber_data *jd = GJ_GC(gjc)->proto_data; |
2086 | 2100 char idle_time[32]; |
3630 | 2101 |
2086 | 2102 id = xmlnode_get_attrib(iqnode, "id"); |
2103 from = xmlnode_get_attrib(iqnode, "from"); | |
2104 | |
2105 x = jutil_iqnew(JPACKET__RESULT, "jabber:iq:last"); | |
2106 | |
2107 xmlnode_put_attrib(x, "to", from); | |
2108 xmlnode_put_attrib(x, "id", id); | |
2109 querytag = xmlnode_get_tag(x, "query"); | |
2110 g_snprintf(idle_time, sizeof idle_time, "%ld", jd->idle ? time(NULL) - jd->idle : 0); | |
2111 xmlnode_put_attrib(querytag, "seconds", idle_time); | |
2112 | |
2956 | 2113 gjab_send(gjc, x); |
2086 | 2114 xmlnode_free(x); |
2115 } | |
2116 | |
2956 | 2117 /* |
2118 * delete == TRUE: delete found entry | |
2119 * | |
2120 * returns pointer to (local) copy of value if found, NULL otherwise | |
2121 * | |
2122 * Note: non-reentrant! Local static storage re-used on subsequent calls. | |
2123 * If you're going to need to keep the returned value, make a copy! | |
2124 */ | |
2125 static gchar *jabber_track_queries(GHashTable *queries, gchar *key, gboolean delete) | |
2126 { | |
2127 gpointer my_key, my_val; | |
2128 static gchar *ret_val = NULL; | |
2129 | |
2130 if(ret_val != NULL) { | |
2131 g_free(ret_val); | |
2132 ret_val = NULL; | |
2133 } | |
2134 | |
2135 /* self-protection */ | |
2136 if(queries != NULL && key != NULL) { | |
2137 if(g_hash_table_lookup_extended(queries, key, &my_key, &my_val)) { | |
2138 ret_val = g_strdup((gchar *) my_val); | |
2139 if(delete) { | |
2140 g_hash_table_remove(queries, key); | |
2141 g_free(my_key); | |
2142 g_free(my_val); | |
2143 } | |
2144 } | |
2145 } | |
2146 | |
2147 return(ret_val); | |
2148 } | |
2149 | |
2150 static void jabber_handlepacket(gjconn gjc, jpacket p) | |
2086 | 2151 { |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
2152 char *id; |
2086 | 2153 switch (p->type) { |
2154 case JPACKET_MESSAGE: | |
2956 | 2155 jabber_handlemessage(gjc, p); |
2086 | 2156 break; |
2157 case JPACKET_PRESENCE: | |
2956 | 2158 jabber_handlepresence(gjc, p); |
2086 | 2159 break; |
2160 case JPACKET_IQ: | |
2161 debug_printf("jpacket_subtype: %d\n", jpacket_subtype(p)); | |
2162 | |
2956 | 2163 id = xmlnode_get_attrib(p->x, "id"); |
2164 if (id != NULL && !strcmp(id, IQID_AUTH)) { | |
2165 jabber_handleauthresp(gjc, p); | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
2166 break; |
2086 | 2167 } |
2168 | |
2169 if (jpacket_subtype(p) == JPACKET__SET) { | |
2956 | 2170 xmlnode querynode; |
2171 querynode = xmlnode_get_tag(p->x, "query"); | |
2172 if (NSCHECK(querynode, "jabber:iq:roster")) { | |
2173 jabber_handlebuddy(gjc, xmlnode_get_firstchild(querynode)); | |
3630 | 2174 } else if(NSCHECK(querynode, "jabber:iq:oob")) { |
2175 jabber_handleoob(gjc, p->x); | |
2956 | 2176 } |
2086 | 2177 } else if (jpacket_subtype(p) == JPACKET__GET) { |
3770 | 2178 xmlnode querynode; |
2086 | 2179 querynode = xmlnode_get_tag(p->x, "query"); |
3770 | 2180 if (NSCHECK(querynode, NS_VERSION)) { |
2181 jabber_handleversion(gjc, p->x); | |
2086 | 2182 } else if (NSCHECK(querynode, NS_TIME)) { |
3770 | 2183 jabber_handletime(gjc, p->x); |
2086 | 2184 } else if (NSCHECK(querynode, "jabber:iq:last")) { |
3770 | 2185 jabber_handlelast(gjc, p->x); |
2086 | 2186 } |
2187 } else if (jpacket_subtype(p) == JPACKET__RESULT) { | |
2188 xmlnode querynode, vcard; | |
2189 char *xmlns, *from; | |
2190 | |
2956 | 2191 /* |
2192 * TBD: ISTM maybe this part could use a serious re-work? | |
2193 */ | |
2086 | 2194 from = xmlnode_get_attrib(p->x, "from"); |
2195 querynode = xmlnode_get_tag(p->x, "query"); | |
2196 vcard = xmlnode_get_tag(p->x, "vCard"); | |
2316
ebb5ecb2cd5b
[gaim-migrate @ 2326]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2309
diff
changeset
|
2197 if (!vcard) |
ebb5ecb2cd5b
[gaim-migrate @ 2326]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2309
diff
changeset
|
2198 vcard = xmlnode_get_tag(p->x, "VCARD"); |
2086 | 2199 |
2200 if (NSCHECK(querynode, NS_ROSTER)) { | |
2956 | 2201 jabber_handleroster(gjc, querynode); |
2086 | 2202 } else if (NSCHECK(querynode, NS_VCARD)) { |
2956 | 2203 jabber_track_queries(gjc->queries, id, TRUE); /* delete query track */ |
3770 | 2204 jabber_handlevcard(gjc, querynode, from); |
2316
ebb5ecb2cd5b
[gaim-migrate @ 2326]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2309
diff
changeset
|
2205 } else if (vcard) { |
2956 | 2206 jabber_track_queries(gjc->queries, id, TRUE); /* delete query track */ |
2207 jabber_handlevcard(gjc, vcard, from); | |
2208 } else if((xmlns = xmlnode_get_attrib(querynode, "xmlns")) != NULL) { | |
2209 debug_printf("jabber:iq:query: %s\n", xmlns); | |
2086 | 2210 } else { |
2956 | 2211 char *val; |
2212 | |
2213 debug_printf("jabber:iq: %s\n", xmlnode2str(p->x)); | |
2214 | |
2215 /* handle "null" query results */ | |
2216 if((val = jabber_track_queries(gjc->queries, id, TRUE)) != NULL) { | |
2217 if(strcmp((char *) val, "vCard") == 0) { | |
2218 /* | |
2219 * No actual vCard, but there's other stuff. This | |
2220 * way the user always gets some kind of response. | |
2221 */ | |
2222 jabber_handlevcard(gjc, NULL, from); | |
3257 | 2223 } else if(!strcmp((char *) val, "change_password")) { |
2224 char buf[BUF_LONG]; | |
3311 | 2225 sprintf(buf, _("Password successfully changed.")); |
3257 | 2226 |
3427 | 2227 do_error_dialog(buf, NULL, GAIM_INFO); |
2956 | 2228 } |
2229 } | |
2086 | 2230 } |
2231 | |
2232 } else if (jpacket_subtype(p) == JPACKET__ERROR) { | |
2233 xmlnode xerr; | |
2234 char *from, *errmsg = NULL; | |
2235 int errcode = 0; | |
2236 | |
2237 from = xmlnode_get_attrib(p->x, "from"); | |
2238 xerr = xmlnode_get_tag(p->x, "error"); | |
2239 if (xerr) { | |
2240 errmsg = xmlnode_get_data(xerr); | |
2241 if (xmlnode_get_attrib(xerr, "code")) | |
2242 errcode = atoi(xmlnode_get_attrib(xerr, "code")); | |
2243 } | |
2244 | |
3427 | 2245 from = g_strdup_printf("Jabber Error %d (%s)", errcode, from); |
2246 do_error_dialog(from, errmsg, GAIM_ERROR); | |
2086 | 2247 g_free(from); |
2248 | |
2249 } | |
2250 | |
2251 break; | |
2252 case JPACKET_S10N: | |
2956 | 2253 jabber_handles10n(gjc, p); |
2086 | 2254 break; |
2255 default: | |
2256 debug_printf("jabber: packet type %d (%s)\n", p->type, xmlnode2str(p->x)); | |
2257 } | |
2258 | |
2259 xmlnode_free(p->x); | |
2260 | |
2261 return; | |
2262 } | |
2263 | |
2956 | 2264 static void jabber_handlestate(gjconn gjc, int state) |
2086 | 2265 { |
2266 switch (state) { | |
2267 case JCONN_STATE_OFF: | |
3074 | 2268 if(gjc->was_connected) { |
2269 hide_login_progress_error(GJ_GC(gjc), _("Connection lost")); | |
2270 } else { | |
2271 hide_login_progress(GJ_GC(gjc), _("Unable to connect")); | |
2272 } | |
2956 | 2273 signoff(GJ_GC(gjc)); |
2086 | 2274 break; |
2275 case JCONN_STATE_CONNECTED: | |
3074 | 2276 gjc->was_connected = 1; |
2975 | 2277 set_login_progress(GJ_GC(gjc), 2, _("Connected")); |
2086 | 2278 break; |
2279 case JCONN_STATE_ON: | |
2975 | 2280 set_login_progress(GJ_GC(gjc), 3, _("Requesting Authentication Method")); |
2956 | 2281 gjab_reqauth(gjc); |
2086 | 2282 break; |
2283 default: | |
2284 debug_printf("state change: %d\n", state); | |
2285 } | |
2286 return; | |
2287 } | |
2288 | |
4491 | 2289 static void jabber_login(struct gaim_account *account) |
2086 | 2290 { |
4491 | 2291 struct gaim_connection *gc = new_gaim_conn(account); |
2086 | 2292 struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); |
4917 | 2293 char *loginname = create_valid_jid(account->username, DEFAULT_SERVER, "Gaim"); |
2086 | 2294 |
3311 | 2295 jd->buddies = g_hash_table_new(g_str_hash, g_str_equal); |
2956 | 2296 jd->chats = NULL; /* we have no chats yet */ |
2086 | 2297 |
2975 | 2298 set_login_progress(gc, 1, _("Connecting")); |
2086 | 2299 |
4491 | 2300 if (!(jd->gjc = gjab_new(loginname, account->password, gc))) { |
2086 | 2301 g_free(loginname); |
2302 debug_printf("jabber: unable to connect (jab_new failed)\n"); | |
2975 | 2303 hide_login_progress(gc, _("Unable to connect")); |
2086 | 2304 signoff(gc); |
2305 return; | |
2306 } | |
2307 | |
2308 g_free(loginname); | |
2956 | 2309 gjab_state_handler(jd->gjc, jabber_handlestate); |
2310 gjab_packet_handler(jd->gjc, jabber_handlepacket); | |
2311 jd->gjc->queries = g_hash_table_new(g_str_hash, g_str_equal); | |
2312 gjab_start(jd->gjc); | |
2086 | 2313 } |
2314 | |
2315 static gboolean jabber_destroy_hash(gpointer key, gpointer val, gpointer data) { | |
3770 | 2316 g_free(key); |
2086 | 2317 g_free(val); |
2318 return TRUE; | |
2319 } | |
2320 | |
3311 | 2321 static gboolean jabber_destroy_buddy_hash(gpointer key, gpointer val, gpointer data) { |
2322 struct jabber_buddy_data *jbd = val; | |
2323 while (jbd->resources) { | |
2324 g_free(((jab_res_info) ((GSList *)jbd->resources)->data)->name); | |
2325 if(((jab_res_info) ((GSList *)jbd->resources)->data)->away_msg) | |
2326 g_free(((jab_res_info) ((GSList *)jbd->resources)->data)->away_msg); | |
2327 g_free(((GSList *)jbd->resources)->data); | |
2328 jbd->resources = g_slist_remove(jbd->resources, ((GSList *)jbd->resources)->data); | |
2329 | |
2330 } | |
2331 if(jbd->error_msg) | |
2332 g_free(jbd->error_msg); | |
2333 g_free(key); | |
2334 g_free(jbd); | |
2335 return TRUE; | |
2336 } | |
2337 | |
2338 | |
2086 | 2339 static gboolean jabber_free(gpointer data) |
2340 { | |
2956 | 2341 struct jabber_data *jd = data; |
2342 | |
3236 | 2343 if(jd->gjc != NULL) { |
3486 | 2344 g_free(jd->gjc->sid); |
3236 | 2345 gjab_delete(jd->gjc); |
2346 jd->gjc = NULL; | |
2347 } | |
2956 | 2348 g_free(jd); |
2349 | |
2086 | 2350 return FALSE; |
2351 } | |
2352 | |
2353 static void jabber_close(struct gaim_connection *gc) | |
2354 { | |
2355 struct jabber_data *jd = gc->proto_data; | |
2956 | 2356 |
2357 if(jd) { | |
2358 GSList *jcs = jd->chats; | |
2359 | |
2360 /* Free-up the jabber_chat struct allocs and the list */ | |
2361 while (jcs) { | |
3311 | 2362 gaim_jid_free(((struct jabber_chat *)jcs->data)->gjid); |
2956 | 2363 g_free(jcs->data); |
2364 jcs = jcs->next; | |
2365 } | |
2366 g_slist_free(jd->chats); | |
2367 | |
3311 | 2368 /* Free-up the buddy data hash */ |
2369 if(jd->buddies != NULL) | |
2370 { | |
2371 g_hash_table_foreach_remove(jd->buddies, jabber_destroy_buddy_hash, NULL); | |
2372 g_hash_table_destroy(jd->buddies); | |
2373 jd->buddies = NULL; | |
2956 | 2374 } |
2375 | |
2376 /* Free-up the pending queries memories and the list */ | |
3236 | 2377 if(jd->gjc != NULL && jd->gjc->queries != NULL) { |
2956 | 2378 g_hash_table_foreach_remove(jd->gjc->queries, jabber_destroy_hash, NULL); |
2379 g_hash_table_destroy(jd->gjc->queries); | |
2380 jd->gjc->queries = NULL; | |
2381 } | |
2382 } | |
2300
d2686f757d6e
[gaim-migrate @ 2310]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2289
diff
changeset
|
2383 if (gc->inpa) |
d2686f757d6e
[gaim-migrate @ 2310]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2289
diff
changeset
|
2384 gaim_input_remove(gc->inpa); |
2956 | 2385 |
2386 if(jd) { | |
3613 | 2387 g_timeout_add(0, jabber_free, jd); |
3236 | 2388 if(jd->gjc != NULL) |
2389 xmlnode_free(jd->gjc->current); | |
2956 | 2390 } |
2086 | 2391 gc->proto_data = NULL; |
2392 } | |
2393 | |
3311 | 2394 static int jabber_send_typing(struct gaim_connection *gc, char *who, int typing) |
2395 { | |
2396 xmlnode x, y; | |
2397 char *realwho; | |
2398 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; | |
2399 jab_res_info jri = jabber_find_resource(gc, who); | |
2400 | |
2401 if(!jri || !jri->has_composing) | |
2402 return 0; | |
2403 | |
2404 if((realwho = get_realwho(gjc, who, FALSE, NULL)) == NULL) | |
2405 return 0; | |
3596 | 2406 |
3311 | 2407 x = xmlnode_new_tag("message"); |
2408 xmlnode_put_attrib(x, "to", realwho); | |
2409 xmlnode_insert_tag(x, "gaim"); | |
2410 | |
2411 y = xmlnode_insert_tag(x, "x"); | |
2412 xmlnode_put_attrib(y, "xmlns", "jabber:x:event"); | |
2413 | |
3596 | 2414 if(typing == TYPING) |
3311 | 2415 xmlnode_insert_tag(y, "composing"); |
3596 | 2416 |
3311 | 2417 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2418 xmlnode_free(x); | |
2419 g_free(realwho); | |
2420 return JABBER_TYPING_NOTIFY_INT; | |
2421 } | |
2422 | |
3033 | 2423 static int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags) |
2086 | 2424 { |
2425 xmlnode x, y; | |
3311 | 2426 char *thread_id = NULL; |
2956 | 2427 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2086 | 2428 |
2429 if (!who || !message) | |
2123
56c4382f2909
[gaim-migrate @ 2133]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2112
diff
changeset
|
2430 return 0; |
2086 | 2431 |
2432 x = xmlnode_new_tag("message"); | |
4927 | 2433 xmlnode_put_attrib(x, "to", who); |
2434 | |
2435 thread_id = jabber_get_convo_thread(gjc, who); | |
3311 | 2436 if(thread_id) |
2437 { | |
3769 | 2438 if(strcmp(thread_id, "")) { |
2439 y = xmlnode_insert_tag(x, "thread"); | |
2440 xmlnode_insert_cdata(y, thread_id, -1); | |
2441 } | |
3311 | 2442 g_free(thread_id); |
2443 } | |
2444 | |
2278
00a8b7bcef6c
[gaim-migrate @ 2288]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2232
diff
changeset
|
2445 xmlnode_insert_tag(x, "gaim"); |
2086 | 2446 xmlnode_put_attrib(x, "type", "chat"); |
2447 | |
3311 | 2448 /* let other clients know we support typing notification */ |
2449 y = xmlnode_insert_tag(x, "x"); | |
2450 xmlnode_put_attrib(y, "xmlns", "jabber:x:event"); | |
2451 xmlnode_insert_tag(y, "composing"); | |
2452 | |
2086 | 2453 if (message && strlen(message)) { |
2454 y = xmlnode_insert_tag(x, "body"); | |
3642 | 2455 xmlnode_insert_cdata(y, message, -1); |
2086 | 2456 } |
2457 | |
2956 | 2458 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 2459 xmlnode_free(x); |
2303
f5bf315e6104
[gaim-migrate @ 2313]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2300
diff
changeset
|
2460 return 1; |
2086 | 2461 } |
2462 | |
3105 | 2463 /* |
2464 * Add/update buddy's roster entry on server | |
3349 | 2465 * |
2466 * If "alias" or "group" are NULL, gets them from Gaim's current buddylist values | |
2467 * for the buddy. | |
3105 | 2468 */ |
3867 | 2469 static void jabber_roster_update(struct gaim_connection *gc, const char *name, const char *alias, const char *group) |
3105 | 2470 { |
2471 xmlnode x, y; | |
2472 char *realwho; | |
2473 gjconn gjc; | |
2474 struct buddy *buddy = NULL; | |
2475 struct group *buddy_group = NULL; | |
3867 | 2476 const char *my_alias = NULL; |
2477 const char *my_group = NULL; | |
3770 | 2478 |
3105 | 2479 if(gc && gc->proto_data && ((struct jabber_data *)gc->proto_data)->gjc && name) { |
3311 | 2480 gaim_jid gjid; |
3105 | 2481 gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2482 | |
3311 | 2483 if((realwho = get_realwho(gjc, name, FALSE, &gjid)) == NULL) |
2484 return; | |
2485 | |
2486 /* FIXME: transport */ | |
2487 if(gjid->user == NULL) { | |
2488 g_free(realwho); | |
2489 gaim_jid_free(gjid); | |
2490 return; | |
3105 | 2491 } |
3311 | 2492 gaim_jid_free(gjid); |
3105 | 2493 |
2494 x = jutil_iqnew(JPACKET__SET, NS_ROSTER); | |
2495 y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); | |
2496 xmlnode_put_attrib(y, "jid", realwho); | |
2497 | |
4687 | 2498 buddy = gaim_find_buddy(gc->account, realwho); |
4349 | 2499 |
3349 | 2500 /* |
2501 * See if there's an explict (new?) alias for the buddy or we can pull | |
2502 * one out of current Gaim buddylist data for him. | |
2503 */ | |
2504 if(alias && alias[0] != '\0') { | |
2505 my_alias = alias; | |
4705 | 2506 } else if(buddy && buddy->alias) { |
4227 | 2507 my_alias = buddy->alias; |
3349 | 2508 } |
2509 | |
2510 /* If there's an alias for the buddy, it's not 0-length | |
3105 | 2511 * and it doesn't match his JID, add the "name" attribute. |
2512 */ | |
3349 | 2513 if(my_alias != NULL && my_alias[0] != '\0' && strcmp(realwho, my_alias)) |
3311 | 2514 { |
3642 | 2515 xmlnode_put_attrib(y, "name", my_alias); |
3105 | 2516 } |
2517 | |
2518 /* | |
3349 | 2519 * See if there's an explict (new?) group for the buddy or pull |
2520 * one out of current Gaim buddylist data for him. | |
3105 | 2521 */ |
3349 | 2522 if(group && group[0] != '\0') { |
2523 my_group = group; | |
4687 | 2524 } else if((buddy_group = gaim_find_buddys_group(buddy)) != NULL) { |
3349 | 2525 my_group = buddy_group->name; |
2526 } | |
2527 | |
2528 /* | |
2529 * Send what group the buddy's in along with the roster item. | |
2530 */ | |
2531 if(my_group != NULL && my_group[0] != '\0') { | |
2532 xmlnode z = xmlnode_insert_tag(y, "group"); | |
2533 xmlnode_insert_cdata(z, my_group, -1); | |
3105 | 2534 } |
2535 | |
2536 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); | |
2537 | |
2538 xmlnode_free(x); | |
2539 g_free(realwho); | |
2540 } | |
2541 } | |
2542 | |
3136 | 2543 /* |
3349 | 2544 * Add/update buddy's alias on server |
2545 * | |
2546 * This is just a roster update using existing, local buddylist data | |
2547 */ | |
4269 | 2548 static void jabber_alias_buddy(struct gaim_connection *gc, const char *name, const char *alias) |
3349 | 2549 { |
4269 | 2550 jabber_roster_update(gc, name, alias, NULL); |
3349 | 2551 } |
2552 | |
2553 /* | |
3136 | 2554 * Change buddy's group on server roster |
2555 */ | |
3867 | 2556 static void jabber_group_change(struct gaim_connection *gc, const char *name, const char *old_group, const char *new_group) |
3136 | 2557 { |
3349 | 2558 if(old_group && new_group && strcmp(old_group, new_group)) |
2559 jabber_roster_update(gc, name, NULL, new_group); | |
2560 } | |
2561 | |
2562 /* | |
2563 * Group rename | |
2564 * | |
2565 * Jabber doesn't have "groups," per se. "Group" is simply a JID attribute. | |
2566 * So we iterate through the list of buddies that are in the group and change | |
2567 * the group attribute for each of them. | |
2568 */ | |
2569 static void jabber_rename_group(struct gaim_connection *gc, | |
3867 | 2570 const char *old_group, |
2571 const char *new_group, | |
3349 | 2572 GList *members) |
2573 { | |
2574 if(old_group && new_group && strcmp(old_group, new_group)) | |
2575 while(members) { | |
2576 jabber_group_change(gc, (char *)(members->data), old_group, new_group); | |
2577 members = members->next; | |
2578 } | |
3136 | 2579 } |
2580 | |
3466 | 2581 static void jabber_add_buddy(struct gaim_connection *gc, const char *name) |
2086 | 2582 { |
3136 | 2583 xmlnode x; |
2086 | 2584 char *realwho; |
2956 | 2585 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3311 | 2586 gaim_jid gjid; |
2086 | 2587 |
2588 if (!((struct jabber_data *)gc->proto_data)->did_import) | |
2589 return; | |
2590 | |
3311 | 2591 /* |
2592 * If there's no name or the name is ourself | |
2593 */ | |
2594 if(!name || !strcmp(gc->username, name)) | |
2086 | 2595 return; |
2596 | |
3311 | 2597 if((realwho = get_realwho(gjc, name, FALSE, &gjid)) == NULL) { |
3427 | 2598 char *msg = g_strdup_printf(_("The user %s is an invalid Jabber I.D. and was " |
2599 "therefore not added."), name); | |
2600 do_error_dialog("Unable to add buddy.", _("Jabber Error"), GAIM_ERROR); | |
3311 | 2601 g_free(msg); |
2602 jabber_remove_gaim_buddy(gc, name); | |
2603 return; | |
2086 | 2604 } |
2605 | |
3311 | 2606 /* FIXME: transport */ |
2607 if(gjid->user == NULL) { | |
2608 g_free(realwho); | |
2609 gaim_jid_free(gjid); | |
2610 return; | |
2611 } | |
2612 gaim_jid_free(gjid); | |
2613 | |
2086 | 2614 x = xmlnode_new_tag("presence"); |
2615 xmlnode_put_attrib(x, "to", realwho); | |
2616 xmlnode_put_attrib(x, "type", "subscribe"); | |
2956 | 2617 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2618 xmlnode_free(x); | |
2086 | 2619 |
3349 | 2620 jabber_roster_update(gc, realwho, NULL, NULL); |
3105 | 2621 |
2086 | 2622 g_free(realwho); |
2623 } | |
2624 | |
2681
37d80035e77f
[gaim-migrate @ 2694]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2635
diff
changeset
|
2625 static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group) |
2086 | 2626 { |
3048 | 2627 xmlnode x; |
2086 | 2628 char *realwho; |
2956 | 2629 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2086 | 2630 |
3311 | 2631 if(!name || (realwho = get_realwho(gjc, name, FALSE, NULL)) == NULL) |
2086 | 2632 return; |
2633 | |
2956 | 2634 x = xmlnode_new_tag("presence"); |
2635 xmlnode_put_attrib(x, "to", realwho); | |
2636 xmlnode_put_attrib(x, "type", "unsubscribe"); | |
2637 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); | |
2086 | 2638 g_free(realwho); |
2639 xmlnode_free(x); | |
2640 } | |
2641 | |
4916 | 2642 #if 0 /* Faceprint! Look here! */ |
3314 | 2643 /* |
2644 * Remove a buddy item from the roster entirely | |
2645 */ | |
2646 static void jabber_remove_buddy_roster_item(struct gaim_connection *gc, char *name) | |
2647 { | |
3340 | 2648 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3314 | 2649 char *realwho; |
3340 | 2650 |
2651 if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { | |
2652 xmlnode x = jutil_iqnew(JPACKET__SET, NS_ROSTER); | |
2653 xmlnode y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); | |
2654 xmlnode_put_attrib(y, "jid", realwho); | |
2655 xmlnode_put_attrib(y, "subscription", "remove"); | |
2656 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); | |
2657 g_free(realwho); | |
2658 xmlnode_free(x); | |
2659 } | |
2660 } | |
4916 | 2661 #endif |
3340 | 2662 |
2663 /* | |
2664 * Unsubscribe a buddy from our presence | |
2665 */ | |
2666 static void jabber_unsubscribe_buddy_from_us(struct gaim_connection *gc, char *name) | |
2667 { | |
2668 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; | |
2669 char *realwho; | |
2670 | |
2671 if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { | |
2672 xmlnode g = xmlnode_new_tag("presence"); | |
2673 xmlnode_put_attrib(g, "to", realwho); | |
2674 xmlnode_put_attrib(g, "type", "unsubscribed"); | |
2675 gjab_send(gjc, g); | |
2676 xmlnode_free(g); | |
2677 } | |
2678 } | |
2679 | |
2680 /* | |
2681 * Common code for setting ourselves invisible/visible to buddy | |
2682 */ | |
2683 static void jabber_invisible_to_buddy_common(struct gaim_connection *gc, char *name, gboolean invisible) | |
2684 { | |
3314 | 2685 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3340 | 2686 char *realwho; |
2687 | |
2688 if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { | |
2689 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, realwho); | |
2690 xmlnode g = xmlnode_new_tag("presence"); | |
2691 | |
2692 xmlnode_put_attrib(g, "to", realwho); | |
2693 | |
2694 if(invisible) | |
2695 xmlnode_put_attrib(g, "type", "invisible"); | |
2696 | |
2697 gjab_send(gjc, g); | |
2698 | |
2699 g_free(realwho); | |
2700 xmlnode_free(g); | |
2701 | |
2702 if(jbd) { | |
2703 if(invisible) { | |
2704 jbd->invisible |= JABBER_BUD_INVIS; | |
2705 } else { | |
2706 jbd->invisible &= ~JABBER_BUD_INVIS; | |
2707 } | |
2708 } | |
2709 } | |
2710 } | |
2711 | |
2712 /* | |
2713 * Make ourselves temporarily invisible to a buddy | |
2714 */ | |
2715 static void jabber_invisible_to_buddy(struct gaim_connection *gc, char *name) | |
2716 { | |
2717 jabber_invisible_to_buddy_common(gc, name, TRUE); | |
2718 } | |
2719 | |
2720 /* | |
2721 * Make ourselves visible to a buddy | |
2722 */ | |
2723 static void jabber_visible_to_buddy(struct gaim_connection *gc, char *name) | |
2724 { | |
2725 jabber_invisible_to_buddy_common(gc, name, FALSE); | |
2726 } | |
2727 | |
2728 /* | |
2729 * Function used by the g_hash_table_foreach() in invisible_to_all_buddies() to | |
2730 * actually set the status. | |
2731 * | |
2732 * key is unused | |
2733 * value is the pointer to the jabber_buddy_data struct | |
2734 * data is gboolean: TRUE (invisible) or FALSE (not invisible) | |
2735 */ | |
2736 static void set_invisible_to_buddy_status(gpointer key, gpointer val, gpointer data) { | |
2737 struct jabber_buddy_data *jbd = val; | |
2738 gboolean invisible = (gboolean) data; | |
2739 | |
2740 if(jbd) { | |
2741 if(invisible) { | |
2742 jbd->invisible = JABBER_SERV_INVIS | JABBER_BUD_INVIS; | |
2743 } else { | |
2744 /* | |
2745 * If we've asserted server-level invisibility, cancelling | |
2746 * it removes explicit buddy invisibility settings too. | |
2747 */ | |
2748 if(jbd->invisible & JABBER_SERV_INVIS) | |
2749 jbd->invisible = JABBER_NOT_INVIS; | |
2750 } | |
2751 } | |
2752 } | |
2753 | |
2754 /* | |
2755 * Show we've set ourselves invisible/visible to all buddies on the server | |
2756 * | |
2757 * Used when we set server-wide invisibility so that individual buddy menu | |
2758 * entries show the proper option. | |
2759 */ | |
2760 static void invisible_to_all_buddies(struct gaim_connection *gc, gboolean invisible) | |
2761 { | |
2762 struct jabber_data *jd = gc->proto_data; | |
2763 | |
2764 if(jd->buddies != NULL) | |
2765 g_hash_table_foreach(jd->buddies, set_invisible_to_buddy_status, (gpointer) invisible); | |
3314 | 2766 } |
2767 | |
4687 | 2768 static const char *jabber_list_icon(struct gaim_account *a, struct buddy *b) |
2086 | 2769 { |
4687 | 2770 return "jabber"; |
2771 } | |
4916 | 2772 |
2773 static void jabber_list_emblems(struct buddy *b, char **se, char **sw, char **nw, char **ne) | |
2774 { | |
4927 | 2775 struct jabber_buddy_data *jbd = jabber_find_buddy(b->account->gc, b->name); |
2776 | |
2777 if(jbd) { | |
2778 if (jbd->error_msg) | |
2779 *nw = "error"; | |
2780 if ((jbd->subscription & JABBER_SUB_BOTH) != JABBER_SUB_BOTH) { | |
2781 if(jbd->subscription & JABBER_SUB_PENDING) | |
2782 *ne = "pending"; | |
2783 else if(jbd->subscription & JABBER_SUB_FROM) | |
2784 *ne = "sub_from"; | |
2785 else if(jbd->subscription & JABBER_SUB_TO) | |
2786 *ne = "sub_to"; | |
2787 else | |
2788 *ne = "sub_none"; | |
2789 } | |
2790 } | |
2791 | |
4916 | 2792 if (b->present == 0) { |
2793 *se = "offline"; | |
2794 } else { | |
2795 switch (b->uc) { | |
2796 case UC_AWAY: | |
2797 *se = "away"; | |
2798 break; | |
2799 case UC_CHAT: | |
2800 *se = "chat"; | |
2801 break; | |
2802 case UC_XA: | |
2803 *se = "extendedaway"; | |
2804 break; | |
2805 case UC_DND: | |
2806 *se = "dnd"; | |
2807 break; | |
2808 case UC_ERROR: | |
2809 *se = "error"; | |
2810 break; | |
2811 } | |
2086 | 2812 } |
4916 | 2813 } |
2086 | 2814 |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2815 static GList *jabber_chat_info(struct gaim_connection *gc) |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2816 { |
2956 | 2817 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2818 | |
2819 static char *confserv = NULL; /* this pointer must be persistent */ | |
2820 gchar *server; | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2821 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2822 GList *m = NULL; |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2823 struct proto_chat_entry *pce; |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2824 |
2956 | 2825 /* This is a scientific wild-ass guess... |
2826 * | |
2827 * If there are more than two "components" to the current server name, | |
2828 * lop-off the left-most component and replace with "conference." | |
2829 */ | |
2830 if(confserv != NULL) { | |
2831 g_free(confserv); /* dispose of the old value */ | |
2832 } | |
2833 | |
2834 if((server = g_strdup(gjc->user->server)) == NULL) { | |
2835 confserv = g_strdup(DEFAULT_GROUPCHAT); | |
2836 } else { | |
2837 gchar **splits, **index; | |
2838 gchar *tmp; | |
2839 int cnt = 0; | |
2840 | |
2841 | |
2842 index = splits = g_strsplit(server, ".", -1); /* split the connected server */ | |
2843 | |
2844 while(*(index++)) /* index to the end--counting the parts */ | |
2845 ++cnt; | |
2846 | |
2847 /* | |
2848 * If we've more than two parts, point to the second part. Else point | |
2849 * to the start. | |
2850 */ | |
2851 if(cnt > 2) { | |
2852 index -= cnt; | |
2853 } else { | |
2854 index = splits; | |
2855 } | |
2856 | |
2857 /* Put it together */ | |
2858 confserv = g_strjoin(".", "conference", (tmp = g_strjoinv(".", index)), NULL); | |
2859 | |
2860 g_free(server); /* we don't need this stuff no more */ | |
2861 g_free(tmp); | |
2862 g_strfreev(splits); | |
2863 } | |
2864 | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2865 pce = g_new0(struct proto_chat_entry, 1); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2866 pce->label = _("Room:"); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2867 m = g_list_append(m, pce); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2868 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2869 pce = g_new0(struct proto_chat_entry, 1); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2870 pce->label = _("Server:"); |
2956 | 2871 pce->def = confserv; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2872 m = g_list_append(m, pce); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2873 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2874 pce = g_new0(struct proto_chat_entry, 1); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2875 pce->label = _("Handle:"); |
2956 | 2876 pce->def = gjc->user->user; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2877 m = g_list_append(m, pce); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2878 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2879 return m; |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2880 } |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2881 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2882 static void jabber_join_chat(struct gaim_connection *gc, GList *data) |
2086 | 2883 { |
2884 xmlnode x; | |
2885 char *realwho; | |
2956 | 2886 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2887 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; | |
2086 | 2888 struct jabber_chat *jc; |
3311 | 2889 gaim_jid gjid; |
2086 | 2890 |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2891 if (!data || !data->next || !data->next->next) |
2086 | 2892 return; |
2893 | |
3311 | 2894 realwho = create_valid_jid(data->data, data->next->data, data->next->next->data); |
2086 | 2895 debug_printf("%s\n", realwho); |
2896 | |
3311 | 2897 if((gjid = gaim_jid_new(realwho)) == NULL) { |
3427 | 2898 char *msg = g_strdup_printf("The Jabber I.D. %s is invalid.", realwho); |
2899 do_error_dialog(_("Unable to join chat"), msg, GAIM_ERROR); | |
3236 | 2900 g_free(msg); |
3311 | 2901 g_free(realwho); |
3236 | 2902 return; |
2903 } | |
2956 | 2904 |
3311 | 2905 if((jc = find_any_chat(gc, gjid)) != NULL) { |
2956 | 2906 switch(jc->state) { |
2907 case JCS_PENDING: | |
2908 debug_printf("attempt to re-join already pending Jabber chat! (ignoring)\n"); | |
2909 g_free(realwho); /* yuck! */ | |
3311 | 2910 gaim_jid_free(gjid); |
2956 | 2911 return; |
2912 case JCS_ACTIVE: | |
2913 debug_printf("attempt to re-join already active Jabber chat! (ignoring)\n"); | |
2914 g_free(realwho); /* yuck! */ | |
3311 | 2915 gaim_jid_free(gjid); |
2956 | 2916 return; |
2917 case JCS_CLOSED: | |
2918 debug_printf("rejoining previously closed Jabber chat\n"); | |
2919 break; | |
2920 default: | |
2921 debug_printf("found Jabber chat in unknown state! (ignoring)\n"); | |
2922 g_free(realwho); /* yuck! */ | |
3311 | 2923 gaim_jid_free(gjid); |
2956 | 2924 return; |
2925 } | |
2926 } else { | |
2927 debug_printf("joining completely new Jabber chat\n"); | |
2928 jc = g_new0(struct jabber_chat, 1); | |
3311 | 2929 jc->gjid = gjid; |
2956 | 2930 jc->gc = gc; |
2931 ((struct jabber_data *)gc->proto_data)->chats = g_slist_append(jcs, jc); | |
4687 | 2932 // add_buddy(gc->account, _("Chats"), realwho, realwho); |
2956 | 2933 } |
2934 | |
2935 jc->state = JCS_PENDING; | |
2936 | |
2086 | 2937 x = jutil_presnew(0, realwho, NULL); |
2956 | 2938 gjab_send(gjc, x); |
2086 | 2939 xmlnode_free(x); |
2940 g_free(realwho); | |
2941 } | |
2942 | |
3466 | 2943 static void jabber_chat_invite(struct gaim_connection *gc, int id, const char *message, const char *name) |
2086 | 2944 { |
2945 xmlnode x, y; | |
2946 struct jabber_data *jd = gc->proto_data; | |
2956 | 2947 gjconn gjc = jd->gjc; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2948 struct jabber_chat *jc = NULL; |
2086 | 2949 char *realwho, *subject; |
2950 | |
3311 | 2951 if(!name || (realwho = get_realwho(gjc, name, FALSE, NULL)) == NULL) |
2086 | 2952 return; |
2953 | |
2954 /* find which chat we're inviting to */ | |
2956 | 2955 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) |
2086 | 2956 return; |
2957 | |
2958 x = xmlnode_new_tag("message"); | |
2959 xmlnode_put_attrib(x, "to", realwho); | |
3311 | 2960 |
2086 | 2961 g_free(realwho); |
2962 | |
2963 y = xmlnode_insert_tag(x, "x"); | |
2964 xmlnode_put_attrib(y, "xmlns", "jabber:x:conference"); | |
3311 | 2965 subject = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); |
2086 | 2966 xmlnode_put_attrib(y, "jid", subject); |
2967 g_free(subject); | |
2968 | |
2969 if (message && strlen(message)) { | |
2970 y = xmlnode_insert_tag(x, "body"); | |
3642 | 2971 xmlnode_insert_cdata(y, message, -1); |
2086 | 2972 } |
2973 | |
2956 | 2974 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 2975 xmlnode_free(x); |
2976 } | |
2977 | |
2978 static void jabber_chat_leave(struct gaim_connection *gc, int id) | |
2979 { | |
2980 struct jabber_data *jd = gc->proto_data; | |
2956 | 2981 gjconn gjc = jd->gjc; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2982 struct jabber_chat *jc = NULL; |
3311 | 2983 char *chatname; |
2086 | 2984 xmlnode x; |
2985 | |
2956 | 2986 /* Find out which chat we're leaving */ |
2987 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) | |
2086 | 2988 return; |
2989 | |
3311 | 2990 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); |
2991 x = jutil_presnew(0, chatname, NULL); | |
2992 g_free(chatname); | |
2086 | 2993 xmlnode_put_attrib(x, "type", "unavailable"); |
2956 | 2994 gjab_send(gjc, x); |
2086 | 2995 xmlnode_free(x); |
2996 jc->b = NULL; | |
2997 } | |
2998 | |
2167
edf8c5a70e5b
[gaim-migrate @ 2177]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2162
diff
changeset
|
2999 static int jabber_chat_send(struct gaim_connection *gc, int id, char *message) |
2086 | 3000 { |
3001 xmlnode x, y; | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3002 struct jabber_chat *jc = NULL; |
2086 | 3003 char *chatname; |
2956 | 3004 int retval = 0; |
3005 | |
3006 /* Find out which chat we're sending to */ | |
3007 if((retval = jabber_find_chat_by_convo_id(gc, id, &jc)) != 0) | |
3008 return(retval); | |
2086 | 3009 |
3010 x = xmlnode_new_tag("message"); | |
3311 | 3011 xmlnode_put_attrib(x, "from", jc->gjid->full); |
3012 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); | |
2086 | 3013 xmlnode_put_attrib(x, "to", chatname); |
3014 g_free(chatname); | |
3015 xmlnode_put_attrib(x, "type", "groupchat"); | |
3016 | |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3017 if (message && strlen(message) > strlen("/topic ") && |
4793 | 3018 !g_ascii_strncasecmp(message, "/topic ", strlen("/topic "))) { |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3019 char buf[8192]; |
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3020 y = xmlnode_insert_tag(x, "subject"); |
3642 | 3021 xmlnode_insert_cdata(y, message + strlen("/topic "), -1); |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3022 y = xmlnode_insert_tag(x, "body"); |
3642 | 3023 g_snprintf(buf, sizeof(buf), "/me has changed the subject to: %s", message + strlen("/topic")); |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3024 xmlnode_insert_cdata(y, buf, -1); |
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3025 } else if (message && strlen(message)) { |
2086 | 3026 y = xmlnode_insert_tag(x, "body"); |
3642 | 3027 xmlnode_insert_cdata(y, message, -1); |
2086 | 3028 } |
3029 | |
2956 | 3030 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 3031 xmlnode_free(x); |
2167
edf8c5a70e5b
[gaim-migrate @ 2177]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2162
diff
changeset
|
3032 return 0; |
2086 | 3033 } |
3034 | |
3035 static void jabber_chat_whisper(struct gaim_connection *gc, int id, char *who, char *message) | |
3036 { | |
3037 xmlnode x, y; | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3038 struct jabber_chat *jc = NULL; |
2086 | 3039 char *chatname; |
3040 | |
2956 | 3041 /* Find out which chat we're whispering to */ |
3042 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) | |
2086 | 3043 return; |
3044 | |
3045 x = xmlnode_new_tag("message"); | |
3311 | 3046 xmlnode_put_attrib(x, "from", jc->gjid->full); |
3047 chatname = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who); | |
2086 | 3048 xmlnode_put_attrib(x, "to", chatname); |
3049 g_free(chatname); | |
3050 xmlnode_put_attrib(x, "type", "normal"); | |
3051 | |
3052 if (message && strlen(message)) { | |
3053 y = xmlnode_insert_tag(x, "body"); | |
3642 | 3054 xmlnode_insert_cdata(y, message, -1); |
2086 | 3055 } |
3056 | |
2956 | 3057 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 3058 xmlnode_free(x); |
3059 } | |
3060 | |
3061 static char *jabber_normalize(const char *s) | |
3062 { | |
3063 static char buf[BUF_LEN]; | |
3064 char *t, *u; | |
3065 int x = 0; | |
3066 | |
3067 g_return_val_if_fail((s != NULL), NULL); | |
3068 | |
2956 | 3069 /* Somebody called us with s == NULL once... */ |
3070 if(s == NULL) { | |
3071 return(NULL); | |
3072 } else { | |
4793 | 3073 u = t = g_utf8_strdown(s, -1); |
2956 | 3074 |
3075 while (*t && (x < BUF_LEN - 1)) { | |
3076 if (*t != ' ') | |
3077 buf[x++] = *t; | |
3078 t++; | |
3079 } | |
3080 buf[x] = '\0'; | |
3081 g_free(u); | |
3082 | |
3083 if (!strchr(buf, '@')) { | |
4927 | 3084 strcat(buf, "@" DEFAULT_SERVER); /* this isn't always right, but eh */ |
2956 | 3085 } else if ((u = strchr(strchr(buf, '@'), '/')) != NULL) { |
3086 *u = '\0'; | |
3087 } | |
3088 | |
3089 return buf; | |
2086 | 3090 } |
3091 } | |
3092 | |
3093 static void jabber_get_info(struct gaim_connection *gc, char *who) { | |
3094 xmlnode x; | |
3095 char *id; | |
2956 | 3096 char *realwho; |
2086 | 3097 struct jabber_data *jd = gc->proto_data; |
2956 | 3098 gjconn gjc = jd->gjc; |
2086 | 3099 |
3311 | 3100 if((realwho = get_realwho(gjc, who, TRUE, NULL)) == NULL) |
3101 return; | |
3102 | |
2086 | 3103 x = jutil_iqnew(JPACKET__GET, NS_VCARD); |
2956 | 3104 xmlnode_put_attrib(x, "to", realwho); |
3311 | 3105 |
2956 | 3106 g_free(realwho); |
3107 | |
3108 id = gjab_getid(gjc); | |
2086 | 3109 xmlnode_put_attrib(x, "id", id); |
3110 | |
2956 | 3111 g_hash_table_insert(jd->gjc->queries, g_strdup(id), g_strdup("vCard")); |
3112 | |
3113 gjab_send(gjc, x); | |
2086 | 3114 |
3115 xmlnode_free(x); | |
3311 | 3116 } |
3117 | |
3118 static void jabber_get_error_msg(struct gaim_connection *gc, char *who) { | |
3119 struct jabber_data *jd = gc->proto_data; | |
3120 gjconn gjc = jd->gjc; | |
3121 gchar **str_arr = (gchar **) g_new(gpointer, 3); | |
3122 gchar **ap = str_arr; | |
3123 gchar *realwho, *final; | |
3124 struct jabber_buddy_data *jbd; | |
3125 | |
3126 if((realwho = get_realwho(gjc, who, FALSE, NULL)) == NULL) { | |
3127 g_strfreev(str_arr); | |
3128 return; | |
3129 } | |
3130 | |
3131 jbd = jabber_find_buddy(gc, realwho); | |
3132 | |
3133 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho); | |
3134 *ap++ = g_strdup_printf("<B>Error:</B> %s<BR>\n", jbd->error_msg); | |
3135 *ap = NULL; | |
3770 | 3136 |
3311 | 3137 final= g_strjoinv(NULL, str_arr); |
3770 | 3138 |
3311 | 3139 g_strfreev(str_arr); |
3140 | |
3141 g_show_info_text(gc, realwho, 2, final, NULL); | |
3142 g_free(realwho); | |
3143 g_free(final); | |
2086 | 3144 } |
3145 | |
2956 | 3146 static void jabber_get_away_msg(struct gaim_connection *gc, char *who) { |
3147 struct jabber_data *jd = gc->proto_data; | |
3148 gjconn gjc = jd->gjc; | |
3311 | 3149 int num_resources; |
3150 gaim_jid gjid; | |
3151 char *buddy = get_realwho(gjc, who, FALSE, &gjid); | |
3152 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy); | |
3153 gchar **str_arr; | |
3154 gchar **ap; | |
3155 gchar *realwho, *final; | |
3156 GSList *resources; | |
3157 int i; | |
3158 | |
3159 if(!buddy) | |
3160 return; | |
3161 | |
3162 if(!gjid->resource) { | |
3163 num_resources = g_slist_length(jbd->resources); | |
3164 resources = jbd->resources; | |
3165 } else { | |
3166 num_resources = 1; | |
3167 resources = jbd->resources; | |
3168 while(strcasecmp(((jab_res_info)resources->data)->name, gjid->resource)) | |
3169 resources = resources->next; | |
3170 } | |
3171 | |
3172 gaim_jid_free(gjid); | |
2956 | 3173 |
3174 /* space for all elements: Jabber I.D. + "status" + NULL (list terminator) */ | |
3311 | 3175 str_arr = (gchar **) g_new(gpointer, num_resources*2 + 1); |
3176 ap = str_arr; | |
3177 | |
3178 for(i=0; i<num_resources; i++) | |
3179 { | |
3180 jab_res_info jri = resources->data; | |
4450 | 3181 char *status; |
3311 | 3182 realwho = g_strdup_printf("%s/%s", buddy, jri->name); |
4450 | 3183 status = strdup_withhtml(jabber_lookup_away(gjc, realwho)); |
3311 | 3184 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho); |
4745 | 3185 *ap++ = g_strdup_printf("<B>Status:</B> %s%s%s<BR>\n", jabber_get_state_string(jri->state), status ? ": " : "", status ? status : ""); |
4450 | 3186 g_free(status); |
3311 | 3187 g_free(realwho); |
3188 resources = resources->next; | |
2956 | 3189 } |
3190 | |
3191 *ap = NULL; | |
3770 | 3192 |
3311 | 3193 g_free(buddy); |
2956 | 3194 |
3195 final= g_strjoinv(NULL, str_arr); | |
3196 g_strfreev(str_arr); | |
3197 | |
3311 | 3198 g_show_info_text(gc, who, 2, final, NULL); |
2956 | 3199 g_free(final); |
3770 | 3200 |
2956 | 3201 } |
3202 | |
3203 static void jabber_get_cb_info(struct gaim_connection *gc, int cid, char *who) { | |
3204 struct jabber_chat *jc = NULL; | |
3205 char *realwho; | |
3206 | |
3207 /* Find out which chat */ | |
3208 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0) | |
3209 return; | |
3210 | |
3311 | 3211 realwho = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who); |
2956 | 3212 |
3213 jabber_get_info(gc, realwho); | |
3214 g_free(realwho); | |
3215 } | |
3216 | |
3217 static void jabber_get_cb_away_msg(struct gaim_connection *gc, int cid, char *who) { | |
3218 struct jabber_chat *jc = NULL; | |
3219 char *realwho; | |
3220 | |
3221 /* Find out which chat */ | |
3222 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0) | |
3223 return; | |
3224 | |
3311 | 3225 realwho = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who); |
2956 | 3226 |
3227 jabber_get_away_msg(gc, realwho); | |
3228 g_free(realwho); | |
3229 | |
3230 } | |
3231 | |
4744 | 3232 static char *jabber_tooltip_text(struct buddy *b) |
3233 { | |
4745 | 3234 jab_res_info jri = jabber_find_resource(b->account->gc, b->name); |
3235 if(jri) { | |
4777 | 3236 char *stripped = strip_html(jabber_lookup_away(GC_GJ(b->account->gc), |
4745 | 3237 b->name)); |
4777 | 3238 char *text = NULL; |
3239 char *ret; | |
3240 if(stripped) | |
3241 text = g_markup_escape_text(stripped, strlen(stripped)); | |
3242 ret = g_strdup_printf(_("<b>Status:</b> %s%s%s"), | |
4745 | 3243 jabber_get_state_string(jri->state), text ? ": " : "", |
3244 text ? text : ""); | |
3245 | |
4777 | 3246 if(stripped) { |
3247 g_free(stripped); | |
4745 | 3248 g_free(text); |
4777 | 3249 } |
4745 | 3250 return ret; |
3251 } | |
4744 | 3252 return NULL; |
3253 } | |
3254 | |
4732 | 3255 static char *jabber_status_text(struct buddy *b) |
3256 { | |
3257 if (b->uc & UC_UNAVAILABLE) { | |
4777 | 3258 char *stripped = strip_html(jabber_lookup_away(GC_GJ(b->account->gc), |
4745 | 3259 b->name)); |
4777 | 3260 char *ret; |
3261 if(!stripped) { | |
4745 | 3262 jab_res_info jri = jabber_find_resource(b->account->gc, b->name); |
3263 if(jri) | |
4777 | 3264 stripped = g_strdup(jabber_get_state_string(jri->state)); |
4745 | 3265 } |
4777 | 3266 ret = g_markup_escape_text(stripped, strlen(stripped)); |
3267 g_free(stripped); | |
4745 | 3268 return ret; |
4732 | 3269 } |
3270 return NULL; | |
3271 } | |
3272 | |
2170
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3273 static GList *jabber_buddy_menu(struct gaim_connection *gc, char *who) { |
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3274 GList *m = NULL; |
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3275 struct proto_buddy_menu *pbm; |
4687 | 3276 struct buddy *b = gaim_find_buddy(gc->account, who); |
3311 | 3277 |
3278 if(b->uc == UC_ERROR) | |
3279 { | |
3280 pbm = g_new0(struct proto_buddy_menu, 1); | |
3281 pbm->label = _("View Error Msg"); | |
3282 pbm->callback = jabber_get_error_msg; | |
3283 pbm->gc = gc; | |
3284 m = g_list_append(m, pbm); | |
3285 } else { | |
3340 | 3286 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3287 char *realwho = get_realwho(gjc, who, FALSE, NULL); | |
3288 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, realwho); | |
3289 | |
3290 g_free(realwho); | |
3291 | |
3311 | 3292 pbm = g_new0(struct proto_buddy_menu, 1); |
3293 pbm->label = _("Get Away Msg"); | |
3294 pbm->callback = jabber_get_away_msg; | |
3295 pbm->gc = gc; | |
3296 m = g_list_append(m, pbm); | |
3340 | 3297 |
3298 pbm = g_new0(struct proto_buddy_menu, 1); | |
3299 if(jbd && (jbd->invisible & JABBER_BUD_INVIS)) { | |
3300 pbm->label = _("Un-hide From"); | |
3301 pbm->callback = jabber_visible_to_buddy; | |
3302 } else { | |
3303 pbm->label = _("Temporarily Hide From"); | |
3304 pbm->callback = jabber_invisible_to_buddy; | |
3305 } | |
4916 | 3306 |
3307 pbm->gc = gc; | |
3308 m = g_list_append(m, pbm); | |
3309 pbm = g_new0(struct proto_buddy_menu, 1); | |
3310 pbm->label = _("Cancel Presence Notification"); | |
3311 pbm->callback = jabber_unsubscribe_buddy_from_us; | |
3340 | 3312 pbm->gc = gc; |
3313 m = g_list_append(m, pbm); | |
3311 | 3314 } |
2170
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3315 |
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3316 return m; |
2086 | 3317 } |
3318 | |
2501
227cc42ffa6e
[gaim-migrate @ 2514]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2382
diff
changeset
|
3319 static GList *jabber_away_states(struct gaim_connection *gc) { |
2086 | 3320 GList *m = NULL; |
3321 | |
3322 m = g_list_append(m, "Online"); | |
3323 m = g_list_append(m, "Chatty"); | |
3324 m = g_list_append(m, "Away"); | |
3325 m = g_list_append(m, "Extended Away"); | |
3326 m = g_list_append(m, "Do Not Disturb"); | |
3340 | 3327 m = g_list_append(m, "Invisible"); |
4110 | 3328 m = g_list_append(m, GAIM_AWAY_CUSTOM); |
2086 | 3329 |
3330 return m; | |
3331 } | |
3332 | |
3333 static void jabber_set_away(struct gaim_connection *gc, char *state, char *message) | |
3334 { | |
3335 xmlnode x, y; | |
3336 struct jabber_data *jd = gc->proto_data; | |
2956 | 3337 gjconn gjc = jd->gjc; |
3311 | 3338 GSList *jcs; |
3339 struct jabber_chat *jc; | |
3340 char *chatname; | |
3340 | 3341 gboolean invisible = FALSE; |
2086 | 3342 |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3343 if (gc->away) { |
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3344 g_free(gc->away); |
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3345 gc->away = NULL; |
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3346 } |
2086 | 3347 |
3348 x = xmlnode_new_tag("presence"); | |
3349 | |
3350 if (!strcmp(state, GAIM_AWAY_CUSTOM)) { | |
3351 /* oh goody. Gaim is telling us what to do. */ | |
3352 if (message) { | |
3353 /* Gaim wants us to be away */ | |
3354 y = xmlnode_insert_tag(x, "show"); | |
3355 xmlnode_insert_cdata(y, "away", -1); | |
3356 y = xmlnode_insert_tag(x, "status"); | |
3357 xmlnode_insert_cdata(y, message, -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3358 gc->away = g_strdup(message); |
2086 | 3359 } else { |
3360 /* Gaim wants us to not be away */ | |
3361 /* but for Jabber, we can just send presence with no other information. */ | |
3362 } | |
3363 } else { | |
3364 /* state is one of our own strings. it won't be NULL. */ | |
3365 if (!strcmp(state, "Online")) { | |
3366 /* once again, we don't have to put anything here */ | |
3367 } else if (!strcmp(state, "Chatty")) { | |
3368 y = xmlnode_insert_tag(x, "show"); | |
3369 xmlnode_insert_cdata(y, "chat", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3370 gc->away = g_strdup(""); |
2086 | 3371 } else if (!strcmp(state, "Away")) { |
3372 y = xmlnode_insert_tag(x, "show"); | |
3373 xmlnode_insert_cdata(y, "away", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3374 gc->away = g_strdup(""); |
2086 | 3375 } else if (!strcmp(state, "Extended Away")) { |
3376 y = xmlnode_insert_tag(x, "show"); | |
3377 xmlnode_insert_cdata(y, "xa", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3378 gc->away = g_strdup(""); |
2086 | 3379 } else if (!strcmp(state, "Do Not Disturb")) { |
3380 y = xmlnode_insert_tag(x, "show"); | |
3381 xmlnode_insert_cdata(y, "dnd", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3382 gc->away = g_strdup(""); |
3340 | 3383 } else if (!strcmp(state, "Invisible")) { |
3384 xmlnode_put_attrib(x, "type", "invisible"); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3385 gc->away = g_strdup(""); |
3340 | 3386 invisible = TRUE; |
2086 | 3387 } |
3388 } | |
3389 | |
3311 | 3390 gjab_send(gjc, x); /* Notify "individuals" */ |
3391 | |
3392 /* | |
3393 * As of jabberd-1.4.2: simply sending presence to the server doesn't result in | |
3394 * it being propagated to conference rooms. So we wade thru the list of chats, | |
3395 * sending our new presence status to each and every one. | |
3396 */ | |
3397 for(jcs = jd->chats; jcs; jcs = jcs->next) { | |
3398 jc = jcs->data; | |
3399 if(jc->state == JCS_ACTIVE) { | |
3400 xmlnode_put_attrib(x, "from", jc->gjid->full); | |
3401 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); | |
3402 xmlnode_put_attrib(x, "to", chatname); | |
3403 gjab_send(gjc, x); | |
3404 g_free(chatname); | |
3405 } | |
3406 } | |
3407 | |
2086 | 3408 xmlnode_free(x); |
3340 | 3409 |
3410 invisible_to_all_buddies(gc, invisible); | |
2086 | 3411 } |
3412 | |
3413 static void jabber_set_idle(struct gaim_connection *gc, int idle) { | |
3414 struct jabber_data *jd = (struct jabber_data *)gc->proto_data; | |
3415 debug_printf("jabber_set_idle: setting idle %i\n", idle); | |
3770 | 3416 jd->idle = idle ? time(NULL) - idle : idle; |
2086 | 3417 } |
3418 | |
3419 static void jabber_keepalive(struct gaim_connection *gc) { | |
3420 struct jabber_data *jd = (struct jabber_data *)gc->proto_data; | |
4450 | 3421 gjab_send_raw(jd->gjc, JABBER_KEEPALIVE_STRING); |
2086 | 3422 } |
3423 | |
2956 | 3424 /*---------------------------------------*/ |
3425 /* Jabber "set info" (vCard) support */ | |
3426 /*---------------------------------------*/ | |
3427 | |
3428 /* | |
3429 * V-Card format: | |
3430 * | |
3431 * <vCard prodid='' version='' xmlns=''> | |
3432 * <FN></FN> | |
3433 * <N> | |
3434 * <FAMILY/> | |
3435 * <GIVEN/> | |
3436 * </N> | |
3437 * <NICKNAME/> | |
3438 * <URL/> | |
3439 * <ADR> | |
3440 * <STREET/> | |
3441 * <EXTADD/> | |
3442 * <LOCALITY/> | |
3443 * <REGION/> | |
3444 * <PCODE/> | |
3445 * <COUNTRY/> | |
3446 * </ADR> | |
3447 * <TEL/> | |
3448 * <EMAIL/> | |
3449 * <ORG> | |
3450 * <ORGNAME/> | |
3451 * <ORGUNIT/> | |
3452 * </ORG> | |
3453 * <TITLE/> | |
3454 * <ROLE/> | |
3455 * <DESC/> | |
3456 * <BDAY/> | |
3457 * </vCard> | |
3458 * | |
3459 * See also: | |
3460 * | |
3461 * http://docs.jabber.org/proto/html/vcard-temp.html | |
3462 * http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd | |
3463 */ | |
3464 | |
3465 /* | |
3466 * Cross-reference user-friendly V-Card entry labels to vCard XML tags | |
3467 * and attributes. | |
3468 * | |
3469 * Order is (or should be) unimportant. For example: we have no way of | |
3470 * knowing in what order real data will arrive. | |
3471 * | |
3472 * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag | |
3473 * name, XML tag's parent tag "path" (relative to vCard node). | |
3474 * | |
3475 * List is terminated by a NULL label pointer. | |
3476 * | |
3477 * Entries with no label text, but with XML tag and parent tag | |
3478 * entries, are used by V-Card XML construction routines to | |
3479 * "automagically" construct the appropriate XML node tree. | |
3480 * | |
3481 * Thoughts on future direction/expansion | |
3482 * | |
3483 * This is a "simple" vCard. | |
3484 * | |
3485 * It is possible for nodes other than the "vCard" node to have | |
3486 * attributes. Should that prove necessary/desirable, add an | |
3487 * "attributes" pointer to the vcard_template struct, create the | |
3488 * necessary tag_attr structs, and add 'em to the vcard_dflt_data | |
3489 * array. | |
3490 * | |
3491 * The above changes will (obviously) require changes to the vCard | |
3492 * construction routines. | |
3493 */ | |
3494 | |
3495 struct vcard_template { | |
3496 char *label; /* label text pointer */ | |
3497 char *text; /* entry text pointer */ | |
3498 int visible; /* should entry field be "visible?" */ | |
3499 int editable; /* should entry field be editable? */ | |
3500 char *tag; /* tag text */ | |
3501 char *ptag; /* parent tag "path" text */ | |
3502 char *url; /* vCard display format if URL */ | |
3503 } vcard_template_data[] = { | |
2975 | 3504 {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, |
3505 {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, | |
3506 {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, | |
3507 {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, | |
3508 {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "<A HREF=\"%s\">%s</A>"}, | |
3509 {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, | |
3510 {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, | |
3511 {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, | |
3512 {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, | |
3513 {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, | |
3514 {N_("Country"), NULL, TRUE, TRUE, "COUNTRY", "ADR", NULL}, | |
3515 {N_("Telephone"), NULL, TRUE, TRUE, "TELEPHONE", NULL, NULL}, | |
3516 {N_("Email"), NULL, TRUE, TRUE, "EMAIL", NULL, "<A HREF=\"mailto:%s\">%s</A>"}, | |
3517 {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, | |
3518 {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, | |
3519 {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, | |
3520 {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, | |
3521 {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, | |
3522 {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, | |
2956 | 3523 {"", NULL, TRUE, TRUE, "N", NULL, NULL}, |
3524 {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, | |
3525 {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, | |
3526 {NULL, NULL, 0, 0, NULL, NULL, NULL} | |
3527 }; | |
3528 | |
3529 /* | |
3530 * The "vCard" tag's attibute list... | |
3531 */ | |
3532 struct tag_attr { | |
3533 char *attr; | |
3534 char *value; | |
3535 } vcard_tag_attr_list[] = { | |
3536 {"prodid", "-//HandGen//NONSGML vGen v1.0//EN"}, | |
3537 {"version", "2.0", }, | |
3538 {"xmlns", "vcard-temp", }, | |
3539 {NULL, NULL}, | |
3540 }; | |
3541 | |
3542 | |
3543 /* | |
3544 * V-Card user instructions | |
3545 */ | |
3546 static char *multi_entry_instructions = | |
2975 | 3547 N_("All items below are optional. Enter only the information with which you feel comfortable"); |
3548 static char *entries_title = N_("User Identity"); | |
2956 | 3549 |
3550 /* | |
3551 * Used by routines to parse an XML-encoded string into an xmlnode tree | |
3552 */ | |
3553 typedef struct { | |
3554 XML_Parser parser; | |
3555 xmlnode current; | |
3556 } *xmlstr2xmlnode_parser, xmlstr2xmlnode_parser_struct; | |
3557 | |
3558 | |
3559 /* | |
3560 * Display a Jabber vCard | |
3561 */ | |
3562 static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from) | |
3563 { | |
3564 struct gaim_connection *gc = GJ_GC(gjc); | |
3565 char *cdata, *status; | |
3566 struct vcard_template *vc_tp = vcard_template_data; | |
3567 | |
3568 /* space for all vCard elements + Jabber I.D. + "status" + NULL (list terminator) */ | |
3569 gchar **str_arr = (gchar **) g_new(gpointer, | |
3570 (sizeof(vcard_template_data)/sizeof(struct vcard_template)) + 3); | |
3571 gchar **ap = str_arr; | |
3572 gchar *buddy, *final; | |
3573 | |
4745 | 3574 jab_res_info jri; |
3575 | |
3311 | 3576 if((buddy = get_realwho(gjc, from, TRUE, NULL)) == NULL) { |
3577 g_strfreev(str_arr); | |
3578 return; | |
2956 | 3579 } |
3311 | 3580 |
4745 | 3581 jri = jabber_find_resource(GJ_GC(gjc), buddy); |
3582 | |
2956 | 3583 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", buddy); |
3584 | |
3585 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
3586 if(strcmp(vc_tp->tag, "DESC") == 0) | |
3587 continue; /* special handling later */ | |
3588 if(vc_tp->ptag == NULL) { | |
3589 cdata = xmlnode_get_tag_data(querynode, vc_tp->tag); | |
3590 } else { | |
3591 gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag); | |
3592 cdata = xmlnode_get_tag_data(querynode, tag); | |
3593 g_free(tag); | |
3594 } | |
3595 if(cdata != NULL) { | |
3596 if(vc_tp->url == NULL) { | |
3597 *ap++ = g_strdup_printf("<B>%s:</B> %s<BR>\n", vc_tp->label, cdata); | |
3598 } else { | |
3599 gchar *fmt = g_strdup_printf("<B>%%s:</B> %s<BR>\n", vc_tp->url); | |
3600 *ap++ = g_strdup_printf(fmt, vc_tp->label, cdata, cdata); | |
3601 g_free(fmt); | |
3602 } | |
3603 } | |
3604 } | |
3605 | |
4745 | 3606 |
4450 | 3607 status = strdup_withhtml(jabber_lookup_away(gjc, buddy)); |
4745 | 3608 *ap++ = g_strdup_printf("<B>Status:</B> %s%s%s<BR>\n", |
3609 jri ? jabber_get_state_string(jri->state) : "", | |
3610 jri && status ? ": " : "", status ? status : ""); | |
4450 | 3611 g_free(status); |
2956 | 3612 |
3613 /* | |
3614 * "Description" handled as a special case: get a copy of the | |
3615 * string and HTML-ize. | |
3616 */ | |
3617 if((cdata = xmlnode_get_tag_data(querynode, "DESC")) != NULL) { | |
3618 gchar *tmp = g_strdup_printf("<HR>%s<BR>", cdata); | |
3619 *ap++ = strdup_withhtml(tmp); | |
3620 g_free(tmp); | |
3621 } | |
3622 | |
3623 *ap = NULL; | |
3624 | |
3625 final= g_strjoinv(NULL, str_arr); | |
3626 g_strfreev(str_arr); | |
3627 | |
3628 g_show_info_text(gc, buddy, 2, final, NULL); | |
3629 g_free(buddy); | |
3630 g_free(final); | |
3631 } | |
3632 | |
3633 /* | |
3634 * Used by XML_Parse on parsing CDATA | |
3635 */ | |
3636 static void xmlstr2xmlnode_charData(void *userdata, const char *s, int slen) | |
3637 { | |
3638 xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; | |
3639 | |
3640 if (xmlp->current) | |
3641 xmlnode_insert_cdata(xmlp->current, s, slen); | |
3642 } | |
3643 | |
3644 /* | |
3645 * Used by XML_Parse to start or append to an xmlnode | |
3646 */ | |
3647 static void xmlstr2xmlnode_startElement(void *userdata, const char *name, const char **attribs) | |
3648 { | |
3649 xmlnode x; | |
3650 xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; | |
3651 | |
3652 if (xmlp->current) { | |
3653 /* Append the node to the current one */ | |
3654 x = xmlnode_insert_tag(xmlp->current, name); | |
3655 xmlnode_put_expat_attribs(x, attribs); | |
3656 | |
3657 xmlp->current = x; | |
3658 } else { | |
3659 x = xmlnode_new_tag(name); | |
3660 xmlnode_put_expat_attribs(x, attribs); | |
3661 xmlp->current = x; | |
3662 } | |
3663 } | |
3664 | |
3665 /* | |
3666 * Used by XML_Parse to end an xmlnode | |
3667 */ | |
3668 static void xmlstr2xmlnode_endElement(void *userdata, const char *name) | |
3669 { | |
3670 xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; | |
3671 xmlnode x; | |
3672 | |
3673 if (xmlp->current != NULL && (x = xmlnode_get_parent(xmlp->current)) != NULL) { | |
3674 xmlp->current = x; | |
3675 } | |
3676 } | |
3677 | |
3678 /* | |
3679 * Parse an XML-encoded string into an xmlnode tree | |
3680 * | |
3681 * Caller is responsible for freeing the returned xmlnode | |
3682 */ | |
3683 static xmlnode xmlstr2xmlnode(char *xmlstring) | |
3684 { | |
3685 xmlstr2xmlnode_parser my_parser = g_new(xmlstr2xmlnode_parser_struct, 1); | |
3686 xmlnode x = NULL; | |
3687 | |
3688 my_parser->parser = XML_ParserCreate(NULL); | |
3689 my_parser->current = NULL; | |
3690 | |
3691 XML_SetUserData(my_parser->parser, (void *)my_parser); | |
3692 XML_SetElementHandler(my_parser->parser, xmlstr2xmlnode_startElement, xmlstr2xmlnode_endElement); | |
3693 XML_SetCharacterDataHandler(my_parser->parser, xmlstr2xmlnode_charData); | |
3694 XML_Parse(my_parser->parser, xmlstring, strlen(xmlstring), 0); | |
3695 | |
3696 x = my_parser->current; | |
3697 | |
3698 XML_ParserFree(my_parser->parser); | |
3699 g_free(my_parser); | |
3700 | |
3701 return(x); | |
3702 } | |
3703 | |
3704 /* | |
3705 * Insert a tag node into an xmlnode tree, recursively inserting parent tag | |
3706 * nodes as necessary | |
3707 * | |
3708 * Returns pointer to inserted node | |
3709 * | |
3710 * Note to hackers: this code is designed to be re-entrant (it's recursive--it | |
3711 * calls itself), so don't put any "static"s in here! | |
3712 */ | |
3713 static xmlnode insert_tag_to_parent_tag(xmlnode start, const char *parent_tag, const char *new_tag) | |
3714 { | |
3715 xmlnode x = NULL; | |
3716 | |
3717 /* | |
3718 * If the parent tag wasn't specified, see if we can get it | |
3719 * from the vCard template struct. | |
3720 */ | |
3721 if(parent_tag == NULL) { | |
3722 struct vcard_template *vc_tp = vcard_template_data; | |
3723 | |
3724 while(vc_tp->label != NULL) { | |
3725 if(strcmp(vc_tp->tag, new_tag) == 0) { | |
3726 parent_tag = vc_tp->ptag; | |
3727 break; | |
3728 } | |
3729 ++vc_tp; | |
3730 } | |
3731 } | |
3732 | |
3733 /* | |
3734 * If we have a parent tag... | |
3735 */ | |
3736 if(parent_tag != NULL ) { | |
3737 /* | |
3738 * Try to get the parent node for a tag | |
3739 */ | |
3740 if((x = xmlnode_get_tag(start, parent_tag)) == NULL) { | |
3741 /* | |
3742 * Descend? | |
3743 */ | |
3744 char *grand_parent = strcpy(g_malloc(strlen(parent_tag) + 1), parent_tag); | |
3745 char *parent; | |
3746 | |
3747 if((parent = strrchr(grand_parent, '/')) != NULL) { | |
3748 *(parent++) = '\0'; | |
3749 x = insert_tag_to_parent_tag(start, grand_parent, parent); | |
3750 } else { | |
3751 x = xmlnode_insert_tag(start, grand_parent); | |
3752 } | |
3753 g_free(grand_parent); | |
3754 } else { | |
3755 /* | |
3756 * We found *something* to be the parent node. | |
3757 * Note: may be the "root" node! | |
3758 */ | |
3759 xmlnode y; | |
3760 if((y = xmlnode_get_tag(x, new_tag)) != NULL) { | |
3761 return(y); | |
3762 } | |
3763 } | |
3764 } | |
3765 | |
3766 /* | |
3767 * insert the new tag into its parent node | |
3768 */ | |
3769 return(xmlnode_insert_tag((x == NULL? start : x), new_tag)); | |
3770 } | |
3771 | |
3772 /* | |
3773 * Find the tag name for a label | |
3774 * | |
3775 * Returns NULL on not found | |
3776 */ | |
3777 static char *tag_for_label(const char *label) | |
3778 { | |
3779 struct vcard_template *vc_tp = vcard_template_data; | |
3780 char *p = NULL; | |
3781 | |
3782 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
3783 if(strcmp(label, vc_tp->label) == 0) { | |
3784 p = vc_tp->tag; | |
3785 break; | |
3786 } | |
3787 } | |
3788 | |
3789 return(p); | |
3790 } | |
3791 | |
3792 /* | |
3793 * Send vCard info to Jabber server | |
3794 */ | |
3795 static void jabber_set_info(struct gaim_connection *gc, char *info) | |
3796 { | |
3797 xmlnode x, vc_node; | |
3798 char *id; | |
3799 struct jabber_data *jd = gc->proto_data; | |
3800 gjconn gjc = jd->gjc; | |
3801 | |
3802 x = xmlnode_new_tag("iq"); | |
3311 | 3803 xmlnode_put_attrib(x, "type", "set"); |
2956 | 3804 |
3805 id = gjab_getid(gjc); | |
3770 | 3806 |
2956 | 3807 xmlnode_put_attrib(x, "id", id); |
3808 | |
3809 /* | |
3810 * Send only if there's actually any *information* to send | |
3811 */ | |
4874 | 3812 vc_node = xmlstr2xmlnode(info); |
3813 | |
3814 if(vc_node) { | |
3815 if (xmlnode_get_name(vc_node) && | |
3816 !g_ascii_strncasecmp(xmlnode_get_name(vc_node), "vcard", 5)) { | |
3817 xmlnode_insert_tag_node(x, vc_node); | |
3818 debug_printf("jabber: vCard packet: %s\n", xmlnode2str(x)); | |
3819 gjab_send(gjc, x); | |
3820 } | |
3821 xmlnode_free(vc_node); | |
2956 | 3822 } |
3823 | |
3824 xmlnode_free(x); | |
3825 } | |
3826 | |
3827 /* | |
3828 * This is the callback from the "ok clicked" for "set vCard" | |
3829 * | |
3830 * Formats GSList data into XML-encoded string and returns a pointer | |
3831 * to said string. | |
3832 * | |
3833 * g_free()'ing the returned string space is the responsibility of | |
3834 * the caller. | |
3835 */ | |
3836 static gchar *jabber_format_info(MultiEntryDlg *b) | |
3837 { | |
3838 xmlnode vc_node; | |
3839 GSList *list; | |
3840 MultiEntryData *med; | |
3841 MultiTextData *mtd; | |
3842 char *p; | |
3843 | |
3844 struct tag_attr *tag_attr; | |
3845 | |
3846 vc_node = xmlnode_new_tag("vCard"); | |
3847 | |
3848 for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) | |
3849 xmlnode_put_attrib(vc_node, tag_attr->attr, tag_attr->value); | |
3850 | |
3851 for(list = b->multi_entry_items; list != NULL; list = list->next) { | |
3852 med = (MultiEntryData *) list->data; | |
3853 if(med->label != NULL && med->text != NULL && (med->text)[0] != '\0') { | |
3854 if((p = tag_for_label(med->label)) != NULL) { | |
3855 xmlnode xp; | |
3856 if((xp = insert_tag_to_parent_tag(vc_node, NULL, p)) != NULL) { | |
3857 xmlnode_insert_cdata(xp, med->text, -1); | |
3858 } | |
3859 } | |
3860 } | |
3861 } | |
3862 | |
3863 for(list = b->multi_text_items; list != NULL; list = list->next) { | |
3864 mtd = (MultiTextData *) list->data; | |
3865 if(mtd->label != NULL && mtd->text != NULL && (mtd->text)[0] != '\0') { | |
3866 if((p = tag_for_label(mtd->label)) != NULL) { | |
3867 xmlnode xp; | |
3868 if((xp = insert_tag_to_parent_tag(vc_node, NULL, p)) != NULL) { | |
3869 xmlnode_insert_cdata(xp, mtd->text, -1); | |
3870 } | |
3871 } | |
3872 } | |
3873 } | |
3874 | |
3875 | |
3876 p = g_strdup(xmlnode2str(vc_node)); | |
3877 xmlnode_free(vc_node); | |
3878 | |
3879 return(p); | |
3880 } | |
3881 | |
3882 /* | |
3883 * This gets executed by the proto action | |
3884 * | |
3885 * Creates a new MultiEntryDlg struct, gets the XML-formatted user_info | |
3886 * string (if any) into GSLists for the (multi-entry) edit dialog and | |
3887 * calls the set_vcard dialog. | |
3888 */ | |
3889 static void jabber_setup_set_info(struct gaim_connection *gc) | |
3890 { | |
3891 MultiEntryData *data; | |
3892 const struct vcard_template *vc_tp; | |
3893 char *user_info; | |
3894 MultiEntryDlg *b = multi_entry_dialog_new(); | |
3895 char *cdata; | |
3896 xmlnode x_vc_data = NULL; | |
4491 | 3897 struct gaim_account *tmp = gc->account; |
3898 b->account = tmp; | |
2956 | 3899 |
3900 | |
3901 /* | |
3902 * Get existing, XML-formatted, user info | |
3903 */ | |
3904 if((user_info = g_malloc(strlen(tmp->user_info) + 1)) != NULL) { | |
3905 strcpy(user_info, tmp->user_info); | |
3906 x_vc_data = xmlstr2xmlnode(user_info); | |
3907 } | |
3908 | |
3909 /* | |
3910 * Set up GSLists for edit with labels from "template," data from user info | |
3911 */ | |
3912 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
3913 if((vc_tp->label)[0] == '\0') | |
3914 continue; | |
3915 if(vc_tp->ptag == NULL) { | |
3916 cdata = xmlnode_get_tag_data(x_vc_data, vc_tp->tag); | |
3917 } else { | |
3918 gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag); | |
3919 cdata = xmlnode_get_tag_data(x_vc_data, tag); | |
3920 g_free(tag); | |
3921 } | |
3922 if(strcmp(vc_tp->tag, "DESC") == 0) { | |
3923 multi_text_list_update(&(b->multi_text_items), | |
3924 vc_tp->label, cdata, TRUE); | |
3925 } else { | |
3926 data = multi_entry_list_update(&(b->multi_entry_items), | |
3927 vc_tp->label, cdata, TRUE); | |
3928 data->visible = vc_tp->visible; | |
3929 data->editable = vc_tp->editable; | |
3930 } | |
3931 } | |
3932 | |
3933 | |
3934 if(x_vc_data != NULL) { | |
3935 xmlnode_free(x_vc_data); | |
3936 } else { | |
3937 /* | |
3938 * Early Beta versions had a different user_info storage format--let's | |
3939 * see if that works. | |
3940 * | |
3941 * This goes away RSN. | |
3942 */ | |
3943 const char *record_separator = "<BR>"; | |
3944 const char *field_separator = ": "; | |
3945 gchar **str_list, **str_list_ptr, **str_list2; | |
3946 | |
3947 if((str_list = g_strsplit(user_info, record_separator, 0)) != NULL) { | |
3948 for(str_list_ptr = str_list; *str_list_ptr != NULL; ++str_list_ptr) { | |
3949 str_list2 = g_strsplit(*str_list_ptr, field_separator, 2); | |
3950 if(str_list2[0] != NULL && str_list2[1] != NULL) { | |
3951 g_strstrip(str_list2[0]); | |
3952 g_strstrip(str_list2[1]); | |
3953 /* this is ugly--so far */ | |
3954 if(strcmp(str_list2[0], "Description") == 0) { | |
3955 multi_text_list_update(&(b->multi_text_items), | |
3956 str_list2[0], str_list2[1], FALSE); | |
3957 } else { | |
3958 multi_entry_list_update(&(b->multi_entry_items), | |
3959 str_list2[0], str_list2[1], FALSE); | |
3960 } | |
3961 } | |
3962 g_strfreev(str_list2); | |
3963 } | |
3964 g_strfreev(str_list); | |
3965 } | |
3966 } | |
3967 | |
3968 if(user_info != NULL) { | |
3969 g_free(user_info); | |
3970 } | |
3971 | |
2975 | 3972 b->title = _("Gaim - Edit Jabber vCard"); |
4074 | 3973 b->role = "set_info"; |
2956 | 3974 b->instructions->text = g_strdup(multi_entry_instructions); |
2975 | 3975 b->entries_title = g_strdup(entries_title); |
2956 | 3976 |
3977 b->custom = (void *) jabber_format_info; | |
3978 | |
3979 show_set_vcard(b); | |
3980 } | |
3981 | |
3982 /*---------------------------------------*/ | |
3983 /* End Jabber "set info" (vCard) support */ | |
3984 /*---------------------------------------*/ | |
3985 | |
3986 /*----------------------------------------*/ | |
3987 /* Jabber "user registration" support */ | |
3988 /*----------------------------------------*/ | |
3989 | |
3990 /* | |
3991 * Three of the following four functions duplicate much of what | |
3992 * exists elsewhere: | |
3993 * | |
3994 * jabber_handleregresp() | |
3995 * gjab_reqreg() | |
3996 * jabber_handle_registration_state() | |
3997 * | |
3998 * It may be that an additional flag could be added to one of | |
3999 * the "local" structs and the duplicated code modified to | |
4000 * account for it--thus eliminating the duplication. Then again: | |
4001 * doing it the way it is may be much cleaner. | |
4002 * | |
4003 * TBD: Code to support requesting additional information server | |
4004 * wants at registration--incl. dialog. | |
4005 */ | |
4006 | |
4007 /* | |
4008 * Like jabber_handlepacket(), only different | |
4009 */ | |
4010 static void jabber_handleregresp(gjconn gjc, jpacket p) | |
4011 { | |
4012 if (jpacket_subtype(p) == JPACKET__RESULT) { | |
4013 xmlnode querynode; | |
4014 | |
4015 if((querynode = xmlnode_get_tag(p->x, "query")) != NULL) { | |
4016 char *xmlns; | |
4017 | |
4018 /* we damn well *better* have this! */ | |
4019 if((xmlns = xmlnode_get_attrib(querynode, "xmlns")) != NULL && | |
4020 strcmp(xmlns, NS_REGISTER) == 0) { | |
4021 | |
4022 char *tag; | |
4023 xmlnode child = xmlnode_get_firstchild(querynode); | |
4024 | |
4025 debug_printf("got registration requirments response!\n"); | |
4026 | |
4027 while(child != NULL) { | |
4028 if((tag = xmlnode_get_name(child)) != NULL) { | |
4029 char *data; | |
4030 | |
4031 fprintf(stderr, "DBG: got node: \"%s\"\n", tag); | |
4032 fflush(stderr); | |
4033 | |
4034 if((data = xmlnode_get_data(child)) != NULL) { | |
4035 fprintf(stderr, "DBG: got data: \"%s\"\n", data); | |
4036 fflush(stderr); | |
4037 } | |
4038 } | |
4039 child = xmlnode_get_nextsibling(child); | |
4040 } | |
4041 } | |
4042 } else { | |
4043 debug_printf("registration successful!\n"); | |
4044 | |
2975 | 4045 hide_login_progress_notice(GJ_GC(gjc), _("Server Registration successful!")); |
2956 | 4046 /* |
4047 * TBD: is this the correct way to do away with a | |
4048 * gaim_connection and all its associated memory | |
4049 * allocs, etc.? | |
4050 */ | |
4051 signoff(GJ_GC(gjc)); | |
4052 } | |
4053 | |
4054 } else { | |
4055 xmlnode xerr; | |
4056 char *errmsg = NULL; | |
4057 int errcode = 0; | |
4058 struct jabber_data *jd = GJ_GC(gjc)->proto_data; | |
4059 | |
4060 debug_printf("registration failed\n"); | |
4061 xerr = xmlnode_get_tag(p->x, "error"); | |
4062 if (xerr) { | |
4063 char msg[BUF_LONG]; | |
4064 errmsg = xmlnode_get_data(xerr); | |
4065 if (xmlnode_get_attrib(xerr, "code")) { | |
4066 errcode = atoi(xmlnode_get_attrib(xerr, "code")); | |
4067 g_snprintf(msg, sizeof(msg), "Error %d: %s", errcode, errmsg); | |
4068 } else | |
4069 g_snprintf(msg, sizeof(msg), "%s", errmsg); | |
4070 hide_login_progress(GJ_GC(gjc), msg); | |
4071 } else { | |
2975 | 4072 hide_login_progress(GJ_GC(gjc), _("Unknown registration error")); |
2956 | 4073 } |
4074 | |
4075 jd->die = TRUE; | |
4076 } | |
4077 } | |
4078 | |
4079 /* | |
4080 * Like gjab_reqauth(), only different | |
4081 */ | |
4082 static void gjab_reqreg(gjconn gjc) | |
4083 { | |
4084 xmlnode x, y, z; | |
4085 char *user; | |
4086 | |
4087 if (!gjc) | |
4088 return; | |
4089 | |
4090 x = jutil_iqnew(JPACKET__SET, NS_REGISTER); | |
4091 y = xmlnode_get_tag(x, "query"); | |
4092 | |
4093 user = gjc->user->user; | |
4094 | |
4095 if (user) { | |
4096 z = xmlnode_insert_tag(y, "username"); | |
4097 xmlnode_insert_cdata(z, user, -1); | |
4098 } | |
4099 z = xmlnode_insert_tag(y, "password"); | |
4100 xmlnode_insert_cdata(z, gjc->pass, -1); | |
4101 | |
4102 debug_printf("jabber: registration packet: %s\n", xmlnode2str(x)); | |
4103 gjab_send(gjc, x); | |
4104 xmlnode_free(x); | |
4105 } | |
4106 | |
4107 /* | |
4108 * Like jabber_handlestate(), only different | |
4109 */ | |
4110 static void jabber_handle_registration_state(gjconn gjc, int state) | |
4111 { | |
4112 switch (state) { | |
4113 case JCONN_STATE_OFF: | |
3074 | 4114 if(gjc->was_connected) { |
4115 hide_login_progress_error(GJ_GC(gjc), _("Connection lost")); | |
4116 } else { | |
4117 hide_login_progress(GJ_GC(gjc), _("Unable to connect")); | |
4118 } | |
2956 | 4119 signoff(GJ_GC(gjc)); |
4120 break; | |
4121 case JCONN_STATE_CONNECTED: | |
3074 | 4122 gjc->was_connected = 1; |
2956 | 4123 /* |
4124 * TBD? | |
2975 | 4125 set_login_progress(GJ_GC(gjc), 2, _("Connected")); |
2956 | 4126 */ |
4127 break; | |
4128 case JCONN_STATE_ON: | |
4129 /* | |
4130 * TBD? | |
2975 | 4131 set_login_progress(GJ_GC(gjc), 3, _("Requesting Authentication Method")); |
2956 | 4132 */ |
4133 gjab_reqreg(gjc); | |
4134 /* | |
4135 * TBD: A work-in-progress | |
4136 gjab_reqregreqs(gjc); | |
4137 */ | |
4138 break; | |
4139 default: | |
4140 debug_printf("state change: %d\n", state); | |
4141 } | |
4142 return; | |
4143 } | |
4144 | |
4145 /* | |
4146 * Like jabber_login(), only different | |
4147 */ | |
4491 | 4148 void jabber_register_user(struct gaim_account *account) |
2956 | 4149 { |
4491 | 4150 struct gaim_connection *gc = new_gaim_conn(account); |
2956 | 4151 struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); |
4917 | 4152 char *loginname = create_valid_jid(account->username, DEFAULT_SERVER, "Gaim"); |
2956 | 4153 |
4154 /* | |
4155 * These do nothing during registration | |
4156 */ | |
3311 | 4157 jd->buddies = NULL; |
2956 | 4158 jd->chats = NULL; |
4159 | |
4491 | 4160 if ((jd->gjc = gjab_new(loginname, account->password, gc)) == NULL) { |
2956 | 4161 g_free(loginname); |
4162 debug_printf("jabber: unable to connect (jab_new failed)\n"); | |
2975 | 4163 hide_login_progress(gc, _("Unable to connect")); |
2956 | 4164 signoff(gc); |
4165 } else { | |
4166 gjab_state_handler(jd->gjc, jabber_handle_registration_state); | |
4167 gjab_packet_handler(jd->gjc, jabber_handleregresp); | |
4168 jd->gjc->queries = NULL; | |
4169 gjab_start(jd->gjc); | |
4170 } | |
4171 | |
4172 g_free(loginname); | |
4173 } | |
4174 | |
4175 /*----------------------------------------*/ | |
4176 /* End Jabber "user registration" support */ | |
4177 /*----------------------------------------*/ | |
4178 | |
4333 | 4179 static GList *jabber_actions(struct gaim_connection *gc) |
2956 | 4180 { |
4181 GList *m = NULL; | |
4333 | 4182 struct proto_actions_menu *pam; |
4183 | |
4184 pam = g_new0(struct proto_actions_menu, 1); | |
4185 pam->label = _("Set User Info"); | |
4186 pam->callback = jabber_setup_set_info; | |
4187 pam->gc = gc; | |
4188 m = g_list_append(m, pam); | |
4189 | |
2956 | 4190 /* |
4333 | 4191 pam = g_new0(struct proto_actions_menu, 1); |
4192 pam->label = _("Set Dir Info"); | |
4193 pam->callback = show_set_dir; | |
4194 pam->gc = gc; | |
4195 m = g_list_append(m, pam); | |
3257 | 4196 */ |
4333 | 4197 |
4198 pam = g_new0(struct proto_actions_menu, 1); | |
4199 pam->label = _("Change Password"); | |
4200 pam->callback = show_change_passwd; | |
4201 pam->gc = gc; | |
4202 m = g_list_append(m, pam); | |
2956 | 4203 |
4204 return m; | |
4205 } | |
4206 | |
3630 | 4207 G_MODULE_EXPORT void jabber_init(struct prpl *ret) |
2086 | 4208 { |
4209 /* the NULL's aren't required but they're nice to have */ | |
4966 | 4210 struct proto_user_split *pus; |
3572 | 4211 struct proto_user_opt *puo; |
2086 | 4212 ret->protocol = PROTO_JABBER; |
4213 ret->options = OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_CHAT_TOPIC; | |
3572 | 4214 ret->name = g_strdup("Jabber"); |
2086 | 4215 ret->list_icon = jabber_list_icon; |
4916 | 4216 ret->list_emblems = jabber_list_emblems; |
4732 | 4217 ret->status_text = jabber_status_text; |
4744 | 4218 ret->tooltip_text = jabber_tooltip_text; |
2086 | 4219 ret->away_states = jabber_away_states; |
2956 | 4220 ret->actions = jabber_actions; |
2086 | 4221 ret->buddy_menu = jabber_buddy_menu; |
4222 ret->login = jabber_login; | |
4223 ret->close = jabber_close; | |
4224 ret->send_im = jabber_send_im; | |
2956 | 4225 ret->set_info = jabber_set_info; |
2086 | 4226 ret->get_info = jabber_get_info; |
2956 | 4227 ret->get_cb_info = jabber_get_cb_info; |
4228 ret->get_cb_away = jabber_get_cb_away_msg; | |
2086 | 4229 ret->set_away = jabber_set_away; |
4230 ret->set_dir = NULL; | |
4231 ret->get_dir = NULL; | |
4232 ret->dir_search = NULL; | |
4233 ret->set_idle = jabber_set_idle; | |
3257 | 4234 ret->change_passwd = jabber_change_passwd; |
2086 | 4235 ret->add_buddy = jabber_add_buddy; |
4236 ret->add_buddies = NULL; | |
4237 ret->remove_buddy = jabber_remove_buddy; | |
4238 ret->add_permit = NULL; | |
4239 ret->add_deny = NULL; | |
4240 ret->rem_permit = NULL; | |
4241 ret->rem_deny = NULL; | |
4242 ret->set_permit_deny = NULL; | |
4243 ret->warn = NULL; | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
4244 ret->chat_info = jabber_chat_info; |
2086 | 4245 ret->join_chat = jabber_join_chat; |
4246 ret->chat_invite = jabber_chat_invite; | |
4247 ret->chat_leave = jabber_chat_leave; | |
4248 ret->chat_whisper = jabber_chat_whisper; | |
4249 ret->chat_send = jabber_chat_send; | |
4250 ret->keepalive = jabber_keepalive; | |
4251 ret->normalize = jabber_normalize; | |
2956 | 4252 ret->register_user = jabber_register_user; |
3349 | 4253 ret->alias_buddy = jabber_alias_buddy; |
3136 | 4254 ret->group_buddy = jabber_group_change; |
3311 | 4255 ret->send_typing = jabber_send_typing; |
4256 ret->convo_closed = jabber_convo_closed; | |
3349 | 4257 ret->rename_group = jabber_rename_group; |
4508
4c40fccbd7c9
[gaim-migrate @ 4784]
Christian Hammond <chipx86@chipx86.com>
parents:
4491
diff
changeset
|
4258 |
4966 | 4259 pus = g_new0(struct proto_user_split, 1); |
4260 pus->sep = '@'; | |
4261 pus->label = g_strdup(_("Server:")); | |
4262 pus->def = g_strdup("jabber.org"); | |
4263 ret->user_splits = g_list_append(ret->user_splits, pus); | |
4264 | |
4265 pus = g_new0(struct proto_user_split, 1); | |
4266 pus->sep = '/'; | |
4267 pus->label = g_strdup(_("Resource:")); | |
4268 pus->def = g_strdup("Gaim"); | |
4269 ret->user_splits = g_list_append(ret->user_splits, pus); | |
4270 | |
3572 | 4271 puo = g_new0(struct proto_user_opt, 1); |
4591 | 4272 puo->label = g_strdup(_("Port:")); |
4927 | 4273 puo->def = g_strdup_printf("%d", DEFAULT_PORT); |
4591 | 4274 puo->pos = USEROPT_PORT; |
4275 ret->user_opts = g_list_append(ret->user_opts, puo); | |
4276 | |
4277 puo = g_new0(struct proto_user_opt, 1); | |
4917 | 4278 puo->label = g_strdup(_("Connect Server:")); |
4589 | 4279 puo->def = g_strdup(""); |
4280 puo->pos = USEROPT_CONN_SERVER; | |
4281 ret->user_opts = g_list_append(ret->user_opts, puo); | |
4282 | |
2086 | 4283 my_protocol = ret; |
4284 } | |
4285 | |
4286 #ifndef STATIC | |
4287 | |
3630 | 4288 G_MODULE_EXPORT void gaim_prpl_init(struct prpl *prpl) |
2086 | 4289 { |
3572 | 4290 jabber_init(prpl); |
4291 prpl->plug->desc.api_version = PLUGIN_API_VERSION; | |
2086 | 4292 } |
4293 | |
4294 #endif | |
3311 | 4295 |
4296 /* | |
4297 * Local variables: | |
4298 * c-indentation-style: k&r | |
4299 * c-basic-offset: 8 | |
4300 * indent-tabs-mode: notnil | |
4301 * End: | |
4302 * | |
4303 * vim: shiftwidth=8: | |
4304 */ |