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