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