comparison src/protocols/jabber/jabber.c @ 3311:522f37c9f9d2

[gaim-migrate @ 3329] Added typing notification and improved support for Jabber resources. (Thanks, Nathan Walp) Fixed problem with Gaim crashing on non-ASCII buddy alias (Jabber "name" attribute) chars. (Thanks, Ho-seok Lee) Plugged memory leaks and fixed problem with away status not being propagated to conference rooms for jabberd 1.4.2 and above. committer: Tailor Script <tailor@pidgin.im>
author Jim Seymour <jseymour>
date Sat, 15 Jun 2002 17:24:07 +0000
parents 778646c2adbc
children 52db87ab4083
comparison
equal deleted inserted replaced
3310:3d20b3e7f840 3311:522f37c9f9d2
76 #define DEFAULT_GROUPCHAT "conference.jabber.org" 76 #define DEFAULT_GROUPCHAT "conference.jabber.org"
77 #define DEFAULT_PORT 5222 77 #define DEFAULT_PORT 5222
78 78
79 #define USEROPT_PORT 0 79 #define USEROPT_PORT 0
80 80
81 #define JABBER_TYPING_NOTIFY_INT 15 /* Delay (in seconds) between sending typing notifications */
82
81 /* 83 /*
82 * Note: "was_connected" may seem redundant, but it was needed and I 84 * Note: "was_connected" may seem redundant, but it was needed and I
83 * didn't want to touch the Jabber state stuff not specific to Gaim. 85 * didn't want to touch the Jabber state stuff not specific to Gaim.
84 */ 86 */
85 typedef struct gjconn_struct { 87 typedef struct gjconn_struct {
133 */ 135 */
134 struct jabber_data { 136 struct jabber_data {
135 gjconn gjc; 137 gjconn gjc;
136 gboolean did_import; 138 gboolean did_import;
137 GSList *chats; 139 GSList *chats;
138 GHashTable *hash;
139 time_t idle; 140 time_t idle;
140 gboolean die; 141 gboolean die;
142 GHashTable *buddies;
141 }; 143 };
144
145 /*
146 * It is *this* to which we point the buddy proto_data
147 */
148 struct jabber_buddy_data {
149 GSList *resources;
150 char *error_msg;
151 };
152
153 /*
154 * per-resource info
155 */
156 typedef struct jabber_resource_info {
157 char *name;
158 int priority;
159 int state;
160 char *away_msg;
161 char *thread_id;
162 gboolean has_composing;
163 } *jab_res_info;
164
165 /*
166 * For our own jid handling
167 *
168 * We do our own so we can cleanly parse buddy names
169 * (user@server/resource) and rid ourselves of the
170 * struct when we're done with it. The Jabber lib
171 * structs last the life of the pool--we frequently
172 * don't want that.
173 *
174 * We use the real jid structs so we can make use of
175 * jid_safe(), jid_cmp() and some others.
176 *
177 * BE CAREFUL using the Jabber lib routines.
178 * Many of them assume pool use and are not
179 * amenable to use with our own!
180 *
181 * We give them special names so we know, throughout
182 * the code, that they're not alloc'd out of pool
183 * memory and we can, and must, dispose of them when
184 * we're done with 'em.
185 */
186 #define gaim_jid_struct jid_struct
187 typedef struct gaim_jid_struct *gaim_jid;
142 188
143 /* 189 /*
144 * Jabber "chat group" info. Pointers to these go in jabber_data 190 * Jabber "chat group" info. Pointers to these go in jabber_data
145 * pending and existing chats lists. 191 * pending and existing chats lists.
146 */ 192 */
147 struct jabber_chat { 193 struct jabber_chat {
148 jid Jid; 194 gaim_jid gjid;
149 struct gaim_connection *gc; 195 struct gaim_connection *gc;
150 struct conversation *b; 196 struct conversation *b;
151 int id; 197 int id;
152 int state; 198 int state;
153 }; 199 };
190 valid = g_strdup_printf("%s/%s", given, resource); 236 valid = g_strdup_printf("%s/%s", given, resource);
191 else 237 else
192 valid = g_strdup(given); 238 valid = g_strdup(given);
193 239
194 return valid; 240 return valid;
241 }
242
243 /*
244 * Dispose of a gaim_jid_struct
245 */
246 static void gaim_jid_free(gaim_jid gjid)
247 {
248 if(gjid) {
249 if(gjid->resource)
250 free(gjid->resource);
251 if(gjid->user)
252 free(gjid->user);
253 if(gjid->server)
254 free(gjid->server);
255 if(gjid->full)
256 free(gjid->full);
257 free(gjid);
258 }
259 }
260
261 /*
262 * Create a new gjid struct
263 *
264 * Unlike jid_new(), also creates "full."
265 *
266 * Shamelessly copied, in part, from jid.c: jid_new()
267 *
268 * Caller is responsible for freeing the space allocated by this via
269 * gaim_jid_free().
270 *
271 * JFIXME: Has a local declaration for jid.c:jid_safe(). I've put in a
272 * request to have that added to libjabber's lib.h file. (JSeymour)
273 */
274 static gaim_jid gaim_jid_new(char *name)
275 {
276 extern jid jid_safe(jid); /* *retch* */
277
278 gaim_jid gjid = NULL;
279
280 if(name && strlen(name)) {
281 char *server, *resource, *type, *str;
282 int full_len = 0;
283
284 /* user@server/resource */
285
286 str = strdup(name); /* we mangle a copy */
287
288 gjid = calloc(1, sizeof(struct gaim_jid_struct));
289
290 if((resource = strstr(str, "/")) != NULL) {
291 *resource = '\0';
292 ++resource;
293 if((full_len = strlen(resource)) > 0) {
294 gjid->resource = strdup(resource);
295 ++full_len; /* for later "/" addition */
296 }
297 } else {
298 resource = str + strlen(str); /* point to end */
299 }
300
301 type = strstr(str, ":");
302 if(type != NULL && type < resource) {
303 *type = '\0';
304 ++type;
305 str = type; /* ignore the type: prefix */
306 }
307
308 server = strstr(str, "@");
309
310 /*
311 * if there's no @, it's just the server address
312 */
313 if(server == NULL || server > resource) {
314 gjid->server = strdup(str);
315 full_len += strlen(str);
316 } else {
317 *server = '\0';
318 ++server;
319 gjid->server = strdup(server);
320 full_len += strlen(server) + 1; /* account for later "@" */
321 if(strlen(str) > 0) {
322 gjid->user = strdup(str);
323 full_len += strlen(str);
324 }
325 }
326
327 free(str);
328
329 if(!jid_safe(gjid)) {
330 gaim_jid_free(gjid);
331 gjid = NULL;
332 } else {
333 if(full_len) {
334 char *s = gjid->full = malloc(++full_len);
335
336 if(gjid->user) {
337 strcpy(s, gjid->user);
338 s += strlen(gjid->user);
339 }
340 if(gjid->server) {
341 if(s > gjid->full)
342 *(s++) = '@';
343 strcpy(s, gjid->server);
344 s += strlen(gjid->server);
345 }
346 if(gjid->resource) {
347 *(s++) = '/';
348 strcpy(s, gjid->resource);
349 }
350 }
351 }
352 }
353
354 return gjid;
355 }
356
357 /*
358 * Get a "username@server" from unadorned "username"
359 *
360 * If there's no "@server" part and "who" doesn't match the
361 * gjconn server (which would indicate that "who" *is* the
362 * server in case of server messages), the gjconn server is
363 * appended.
364 *
365 * If incl_resource is TRUE (non-0), the returned string
366 * includes the "/resource" part (if it exists), otherwise not.
367 *
368 * Allocates space for returned string. Caller is
369 * responsible for freeing it with g_free().
370 *
371 * If "gjid" is non-null, sets that as well. Caller is
372 * reponsible for freeing that via gaim_jid_free() when done
373 * with it.
374 */
375 static gchar *get_realwho(gjconn gjc, char *who, int incl_resource, gaim_jid *gjid)
376 {
377 gaim_jid my_gjid;
378 gchar *my_who;
379 gchar *realwho = NULL;
380
381 if(!(who && who[0])) {
382 return NULL;
383 }
384
385 /*
386 * Bare username and "username" not the server itself?
387 */
388 if(!strchr(who, '@') && strcasecmp(who, gjc->user->server)) {
389 my_who = g_strdup_printf("%s@%s", who, gjc->user->server);
390 } else {
391 my_who = g_strdup(who);
392 }
393
394 if((my_gjid = gaim_jid_new(my_who)) != NULL) {
395 /*
396 * If there's no "user" part, "who" was just the server or perhaps a transport (?)
397 */
398 if(my_gjid->user) {
399 /*
400 * Include "/resource" bit?
401 */
402 if(incl_resource) {
403 realwho = g_strdup(my_gjid->full);
404 } else {
405 realwho = g_strdup_printf("%s@%s", my_gjid->user, my_gjid->server);
406 }
407 } else {
408 realwho = g_strdup(my_gjid->server);
409 }
410 }
411
412 g_free(my_who);
413
414 if(gjid) {
415 *gjid = my_gjid;
416 } else {
417 gaim_jid_free(my_gjid);
418 }
419
420 return realwho;
195 } 421 }
196 422
197 static gjconn gjab_new(char *user, char *pass, void *priv) 423 static gjconn gjab_new(char *user, char *pass, void *priv)
198 { 424 {
199 pool p; 425 pool p;
627 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; 853 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats;
628 struct jabber_chat *jc = NULL; 854 struct jabber_chat *jc = NULL;
629 855
630 while (jcs) { 856 while (jcs) {
631 jc = jcs->data; 857 jc = jcs->data;
632 if (!jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER)) 858 if (!jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER))
633 break; 859 break;
634 jc = NULL; 860 jc = NULL;
635 jcs = jcs->next; 861 jcs = jcs->next;
636 } 862 }
637 863
647 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; 873 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats;
648 struct jabber_chat *jc = NULL; 874 struct jabber_chat *jc = NULL;
649 875
650 while (jcs) { 876 while (jcs) {
651 jc = jcs->data; 877 jc = jcs->data;
652 if (jc->state == JCS_ACTIVE && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER)) 878 if (jc->state == JCS_ACTIVE && !jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER))
653 break; 879 break;
654 jc = NULL; 880 jc = NULL;
655 jcs = jcs->next; 881 jcs = jcs->next;
656 } 882 }
657 883
666 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; 892 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats;
667 struct jabber_chat *jc = NULL; 893 struct jabber_chat *jc = NULL;
668 894
669 while (jcs) { 895 while (jcs) {
670 jc = jcs->data; 896 jc = jcs->data;
671 if (jc->state == JCS_PENDING && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER)) 897 if (jc->state == JCS_PENDING && !jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER))
672 break; 898 break;
673 jc = NULL; 899 jc = NULL;
674 jcs = jcs->next; 900 jcs = jcs->next;
675 } 901 }
676 902
744 970
745 gjab_send(gjc, x); 971 gjab_send(gjc, x);
746 xmlnode_free(x); 972 xmlnode_free(x);
747 } 973 }
748 } 974 }
975
976 static struct jabber_buddy_data* jabber_find_buddy(struct gaim_connection *gc, char *buddy)
977 {
978 struct jabber_data *jd = gc->proto_data;
979 gpointer val;
980 char *realwho;
981
982 if((realwho = get_realwho(jd->gjc, buddy, FALSE, NULL)) == NULL)
983 return NULL;
984
985 val = g_hash_table_lookup(jd->buddies, realwho);
986 if(val) {
987 g_free(realwho);
988 return (struct jabber_buddy_data *)val;
989
990 } else {
991 struct jabber_buddy_data *jbd = g_new0(struct jabber_buddy_data, 1);
992 jbd->error_msg = NULL;
993 jbd->resources = NULL;
994 g_hash_table_insert(jd->buddies, g_strdup(realwho), jbd);
995 g_free(realwho);
996 return jbd;
997 }
998 }
749 999
750 /* 1000 /*
751 * keep track of away msg same as yahoo plugin 1001 * find a resource by name, or if no name given, return the "default" resource
752 */ 1002 * default being the highest priority one.
753 static void jabber_track_away(gjconn gjc, jpacket p, char *name, char *type) 1003 */
754 { 1004
755 struct jabber_data *jd = GJ_GC(gjc)->proto_data; 1005 static jab_res_info jabber_find_resource(struct gaim_connection *gc, char *who)
756 gpointer val = g_hash_table_lookup(jd->hash, name); 1006 {
1007 GSList *resources;
1008 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, who);
1009 jab_res_info jri = NULL;
1010 char *res = strstr(who, "/");
1011
1012 if(res)
1013 res++;
1014
1015 if(jbd)
1016 {
1017 resources = jbd->resources;
1018 while(resources)
1019 {
1020 if(!jri && !res) {
1021 jri = (jab_res_info) resources->data;
1022 } else if(!res) { /* we're looking for the default priority, so... */
1023 if(((jab_res_info) resources->data)->priority >= jri->priority)
1024 jri = (jab_res_info) resources->data;
1025 } else {
1026 if(!strcasecmp(((jab_res_info) resources->data)->name, res)) {
1027 jri = (jab_res_info) resources->data;
1028 break;
1029 }
1030 }
1031 resources = resources->next;
1032 }
1033 }
1034
1035 return jri;
1036 }
1037
1038 /*
1039 * if the resource doesn't exist, create it. otherwise, just update the priority
1040 */
1041 static void jabber_track_resource(struct gaim_connection *gc,
1042 char *buddy,
1043 char *res,
1044 int priority,
1045 int state)
1046 {
1047 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy);
1048
1049 if(jbd && res) {
1050 char *who = g_strdup_printf("%s/%s", buddy, res);
1051 jab_res_info jri = jabber_find_resource(gc, who);
1052 g_free(who);
1053 if(!jri) {
1054 jri = g_new0(struct jabber_resource_info, 1);
1055 jri->name = g_strdup(res);
1056 jri->away_msg = NULL;
1057 jbd->resources = g_slist_append(jbd->resources, jri);
1058 }
1059 jri->priority = priority;
1060 jri->state = state;
1061 }
1062 }
1063
1064 /*
1065 * remove the resource, if it exists
1066 */
1067 static void jabber_remove_resource(struct gaim_connection *gc, char *buddy, char *res)
1068 {
1069 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy);
1070 if(jbd && res) {
1071 char *who = g_strdup_printf("%s/%s", buddy, res);
1072 jab_res_info jri = jabber_find_resource(gc, who);
1073 g_free(who);
1074 if(jri) {
1075 g_free(jri->name);
1076 if(jri->away_msg)
1077 g_free(jri->away_msg);
1078 jbd->resources = g_slist_remove(jbd->resources, jri);
1079 g_free(jri);
1080 }
1081 }
1082 }
1083
1084 /*
1085 * grab the away message for the default resource
1086 */
1087 static char *jabber_lookup_away(gjconn gjc, char *name)
1088 {
1089 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name);
1090
1091 if(!jri || !jri->away_msg)
1092 return _("Unknown");
1093
1094 return jri->away_msg;
1095 }
1096
1097 static void jabber_track_away(gjconn gjc, jpacket p, char *type)
1098 {
757 char *show; 1099 char *show;
758 char *vshow = NULL; 1100 char *vshow = NULL;
759 char *status = NULL; 1101 char *status = NULL;
760 char *msg = NULL; 1102 char *msg = NULL;
761 1103 jab_res_info jri = NULL;
1104
1105 if(!p || !p->from || !p->from->resource || !p->from->user)
1106 return;
1107
1108 jri = jabber_find_resource(GJ_GC(gjc), jid_full(p->from));
1109
1110 if(!jri)
1111 return;
1112
762 if (type && (strcasecmp(type, "unavailable") == 0)) { 1113 if (type && (strcasecmp(type, "unavailable") == 0)) {
763 vshow = _("Unavailable"); 1114 vshow = _("Unavailable");
764 } else { 1115 } else {
765 if((show = xmlnode_get_tag_data(p->x, "show")) != NULL) { 1116 if((show = xmlnode_get_tag_data(p->x, "show")) != NULL) {
766 if (!strcasecmp(show, "away")) { 1117 if (!strcasecmp(show, "away")) {
773 vshow = _("Do Not Disturb"); 1124 vshow = _("Do Not Disturb");
774 } 1125 }
775 } 1126 }
776 } 1127 }
777 1128
778 if (type && (strcasecmp(type, "error") == 0)) { 1129 status = g_strdup(xmlnode_get_tag_data(p->x, "status"));
779 xmlnode enode;
780
781 if((enode = xmlnode_get_tag(p->x, "error")) != NULL) {
782 status = g_strdup_printf(_("Error %s: %s"),
783 xmlnode_get_attrib(enode, "code"), xmlnode_get_data(enode));
784 } else {
785 status = g_strdup(_("Unknown Error in presence"));
786 }
787 } else {
788 status = g_strdup(xmlnode_get_tag_data(p->x, "status"));
789 }
790 1130
791 if(vshow != NULL || status != NULL ) { 1131 if(vshow != NULL || status != NULL ) {
792 /* kinda hokey, but it works :-) */ 1132 /* kinda hokey, but it works :-) */
793 msg = g_strdup_printf("%s%s%s", 1133 msg = g_strdup_printf("%s%s%s",
794 (vshow == NULL? "" : vshow), 1134 (vshow == NULL? "" : vshow),
798 msg = g_strdup(_("Online")); 1138 msg = g_strdup(_("Online"));
799 } 1139 }
800 1140
801 g_free(status); 1141 g_free(status);
802 1142
803 if (val) { 1143 if(jri->away_msg)
804 g_free(val); 1144 g_free(jri->away_msg);
805 g_hash_table_insert(jd->hash, name, msg); 1145
806 } else { 1146 jri->away_msg = msg;
807 g_hash_table_insert(jd->hash, g_strdup(name), msg); 1147 }
808 } 1148
809 } 1149 static void jabber_convo_closed(struct gaim_connection *gc, char *name)
1150 {
1151 jab_res_info jri = jabber_find_resource(gc, name);
1152
1153 if(jri) {
1154 if(jri->thread_id)
1155 g_free(jri->thread_id);
1156
1157 jri->thread_id = NULL;
1158 }
1159 }
1160
1161 static void jabber_track_convo_thread(gjconn gjc, char *name, char *thread_id)
1162 {
1163 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name);
1164
1165 if(jri) {
1166 if(jri->thread_id)
1167 g_free(jri->thread_id);
1168
1169 jri->thread_id = g_strdup(thread_id);
1170 }
1171 }
1172
1173 static char *jabber_get_convo_thread(gjconn gjc, char *name)
1174 {
1175 char *ct = NULL;
1176 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name);
1177
1178 if(jri) {
1179 if(jri->thread_id)
1180 ct = g_strdup(jri->thread_id);
1181 }
1182
1183 return ct;
1184 }
1185
810 1186
811 static time_t iso8601_to_time(char *timestamp) 1187 static time_t iso8601_to_time(char *timestamp)
812 { 1188 {
813 struct tm t; 1189 struct tm t;
814 time_t retval = 0; 1190 time_t retval = 0;
815 1191
816 if(sscanf(timestamp,"%04d%02d%02dT%02d:%02d:%02d", 1192 if(sscanf(timestamp, "%04d%02d%02dT%02d:%02d:%02d",
817 &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec)) 1193 &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec))
818 { 1194 {
819 t.tm_year -= 1900; 1195 t.tm_year -= 1900;
820 t.tm_mon -= 1; 1196 t.tm_mon -= 1;
821 t.tm_isdst = 0; 1197 t.tm_isdst = 0;
833 return retval; 1209 return retval;
834 } 1210 }
835 1211
836 static void jabber_handlemessage(gjconn gjc, jpacket p) 1212 static void jabber_handlemessage(gjconn gjc, jpacket p)
837 { 1213 {
838 xmlnode y, xmlns, subj, z; 1214 xmlnode y, subj;
839 time_t time_sent = time(NULL); 1215 time_t time_sent = time(NULL);
1216 gboolean typing = FALSE;
840 1217
841 char *from = NULL, *msg = NULL, *type = NULL, *topic = NULL; 1218 char *from = NULL, *msg = NULL, *type = NULL, *topic = NULL;
1219 char *thread_id = NULL;
1220 char *conference_room = NULL;
842 char m[BUF_LONG * 2]; 1221 char m[BUF_LONG * 2];
843 1222
844 type = xmlnode_get_attrib(p->x, "type"); 1223 type = xmlnode_get_attrib(p->x, "type");
845 1224
846 z = xmlnode_get_firstchild(p->x); 1225 if ((y = xmlnode_get_tag(p->x, "thread")))
847 1226 thread_id = xmlnode_get_data(y);
848 while(z) 1227
849 { 1228 y = xmlnode_get_firstchild(p->x);
850 if(NSCHECK(z,NS_DELAY)) 1229
851 { 1230 while(y) {
852 char *timestamp = xmlnode_get_attrib(z,"stamp"); 1231 if(NSCHECK(y, NS_DELAY)) {
853 time_sent = iso8601_to_time(timestamp); 1232 char *timestamp = xmlnode_get_attrib(y, "stamp");
854 } 1233 time_sent = iso8601_to_time(timestamp);
855 z = xmlnode_get_nextsibling(z); 1234 } else if(NSCHECK(y, "jabber:x:event")) {
1235 if(xmlnode_get_tag(y, "composing"))
1236 typing = TRUE;
1237 } else if(NSCHECK(y, "jabber:x:conference")) {
1238 conference_room = xmlnode_get_attrib(y, "jid");
1239 }
1240 y = xmlnode_get_nextsibling(y);
856 } 1241 }
857 1242
858 if (!type || !strcasecmp(type, "normal") || !strcasecmp(type, "chat")) { 1243 if (!type || !strcasecmp(type, "normal") || !strcasecmp(type, "chat")) {
859
860 /* XXX namespaces could be handled better. (mid) */
861 if ((xmlns = xmlnode_get_tag(p->x, "x")))
862 type = xmlnode_get_attrib(xmlns, "xmlns");
863 1244
864 from = jid_full(p->from); 1245 from = jid_full(p->from);
865 /* 1246 /*
866 if ((y = xmlnode_get_tag(p->x, "html"))) { 1247 if ((y = xmlnode_get_tag(p->x, "html"))) {
867 msg = xmlnode_get_data(y); 1248 msg = xmlnode_get_data(y);
874 msg = utf8_to_str(msg); 1255 msg = utf8_to_str(msg);
875 1256
876 if (!from) 1257 if (!from)
877 return; 1258 return;
878 1259
879 if (type && !strcasecmp(type, "jabber:x:conference")) { 1260 if (conference_room) {
880 char *room;
881 GList *m = NULL; 1261 GList *m = NULL;
882 char **data; 1262 char **data;
883 1263
884 room = xmlnode_get_attrib(xmlns, "jid"); 1264 data = g_strsplit(conference_room, "@", 2);
885 data = g_strsplit(room, "@", 2);
886 m = g_list_append(m, g_strdup(data[0])); 1265 m = g_list_append(m, g_strdup(data[0]));
887 m = g_list_append(m, g_strdup(data[1])); 1266 m = g_list_append(m, g_strdup(data[1]));
888 m = g_list_append(m, g_strdup(gjc->user->user)); 1267 m = g_list_append(m, g_strdup(gjc->user->user));
889 g_strfreev(data); 1268 g_strfreev(data);
890 1269
891 serv_got_chat_invite(GJ_GC(gjc), room, from, msg, m); 1270 serv_got_chat_invite(GJ_GC(gjc), conference_room, from, msg, m);
892 } else if (msg) { /* whisper */ 1271 } else if (msg) { /* whisper */
893 struct jabber_chat *jc; 1272 struct jabber_chat *jc;
894 g_snprintf(m, sizeof(m), "%s", msg); 1273 g_snprintf(m, sizeof(m), "%s", msg);
895 if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b) 1274 if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b)
896 serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 1, m, time_sent); 1275 serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 1, m,
1276 time_sent);
897 else { 1277 else {
898 int flags = 0; 1278 int flags = 0;
1279 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), jid_full(p->from));
1280 if(jri && typing)
1281 jri->has_composing = TRUE;
899 if (xmlnode_get_tag(p->x, "gaim")) 1282 if (xmlnode_get_tag(p->x, "gaim"))
900 flags = IM_FLAG_GAIMUSER; 1283 flags = IM_FLAG_GAIMUSER;
1284 if ((y = xmlnode_get_tag(p->x, "thread")))
1285 jabber_track_convo_thread(gjc, jid_full(p->from),
1286 xmlnode_get_data(y));
901 if (find_conversation(jid_full(p->from))) 1287 if (find_conversation(jid_full(p->from)))
902 serv_got_im(GJ_GC(gjc), jid_full(p->from), m, flags, time_sent, -1); 1288 serv_got_im(GJ_GC(gjc), jid_full(p->from), m, flags,
1289 time_sent, -1);
903 else { 1290 else {
904 if(p->from->user) { 1291 if(p->from->user) {
905 from = g_strdup_printf("%s@%s", p->from->user, p->from->server); 1292 from = g_strdup_printf("%s@%s", p->from->user,
1293 p->from->server);
906 } else { 1294 } else {
907 /* server message? */ 1295 /* server message? */
908 from = g_strdup(p->from->server); 1296 from = g_strdup(p->from->server);
909 } 1297 }
910 serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1); 1298 serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1);
911 g_free(from); 1299 g_free(from);
912 } 1300 }
913 } 1301 }
1302 } else {
1303 /* a non-message message! */
1304 from = g_strdup_printf("%s@%s", p->from->user, p->from->server);
1305 if(typing)
1306 serv_got_typing(GJ_GC(gjc), from, 0);
1307 else
1308 serv_got_typing_stopped(GJ_GC(gjc), from);
1309 g_free(from);
914 } 1310 }
915 1311
916 if (msg) 1312 if (msg)
917 g_free(msg); 1313 g_free(msg);
918 1314
964 if (p->from->resource) { 1360 if (p->from->resource) {
965 if (!y) { 1361 if (!y) {
966 if (!find_chat_buddy(jc->b, p->from->resource)) { 1362 if (!find_chat_buddy(jc->b, p->from->resource)) {
967 add_chat_buddy(jc->b, p->from->resource); 1363 add_chat_buddy(jc->b, p->from->resource);
968 } else if ((y = xmlnode_get_tag(p->x, "status"))) { 1364 } else if ((y = xmlnode_get_tag(p->x, "status"))) {
969 char *buf; 1365 jabber_track_away(gjc, p, NULL);
970
971 buf = g_strdup_printf("%s@%s/%s",
972 p->from->user, p->from->server, p->from->resource);
973 jabber_track_away(gjc, p, buf, NULL);
974 g_free(buf);
975
976 } 1366 }
977 } else if (jc->b && msg) { 1367 } else if (jc->b && msg) {
978 char buf[8192]; 1368 char buf[8192];
979 1369
980 if (topic) { 1370 if (topic) {
981 char tbuf[8192]; 1371 char tbuf[8192];
982 g_snprintf(tbuf, sizeof(tbuf), "%s", topic); 1372 g_snprintf(tbuf, sizeof(tbuf), "%s", topic);
983 chat_set_topic(jc->b, p->from->resource, tbuf); 1373 chat_set_topic(jc->b, p->from->resource, tbuf);
984 } 1374 }
985
986 1375
987 g_snprintf(buf, sizeof(buf), "%s", msg); 1376 g_snprintf(buf, sizeof(buf), "%s", msg);
988 serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 0, buf, time_sent); 1377 serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 0, buf,
1378 time_sent);
989 } 1379 }
990 } else { /* message from the server */ 1380 } else { /* message from the server */
991 if(jc->b && topic) { 1381 if(jc->b && topic) {
992 char tbuf[8192]; 1382 char tbuf[8192];
993 g_snprintf(tbuf, sizeof(tbuf), "%s", topic); 1383 g_snprintf(tbuf, sizeof(tbuf), "%s", topic);
1005 1395
1006 static void jabber_handlepresence(gjconn gjc, jpacket p) 1396 static void jabber_handlepresence(gjconn gjc, jpacket p)
1007 { 1397 {
1008 char *to, *from, *type; 1398 char *to, *from, *type;
1009 struct buddy *b = NULL; 1399 struct buddy *b = NULL;
1010 jid who; 1400 gaim_jid gjid;
1011 char *buddy; 1401 char *buddy;
1012 xmlnode y; 1402 xmlnode y;
1013 char *show; 1403 char *show;
1014 int state = 0; 1404 int state = 0;
1015 GSList *resources;
1016 char *res;
1017 struct conversation *cnv = NULL; 1405 struct conversation *cnv = NULL;
1018 struct jabber_chat *jc = NULL; 1406 struct jabber_chat *jc = NULL;
1019 1407 int priority = 0;
1408 struct jabber_buddy_data *jbd;
1409
1020 to = xmlnode_get_attrib(p->x, "to"); 1410 to = xmlnode_get_attrib(p->x, "to");
1021 from = xmlnode_get_attrib(p->x, "from"); 1411 from = xmlnode_get_attrib(p->x, "from");
1022 type = xmlnode_get_attrib(p->x, "type"); 1412 type = xmlnode_get_attrib(p->x, "type");
1023 1413
1414 if((buddy = get_realwho(gjc, from, FALSE, &gjid)) == NULL)
1415 return;
1416
1417 if (gjid->user == NULL) {
1418 /* FIXME: transport */
1419 g_free(buddy);
1420 gaim_jid_free(gjid);
1421 return;
1422 }
1423
1424 jbd = jabber_find_buddy(GJ_GC(gjc), buddy);
1425
1426 if(jbd->error_msg) {
1427 g_free(jbd->error_msg);
1428 jbd->error_msg = NULL;
1429 }
1430
1024 if(type && !strcasecmp(type, "error")) { 1431 if(type && !strcasecmp(type, "error")) {
1025 state = UC_ERROR; 1432 state = UC_ERROR;
1433 if((y = xmlnode_get_tag(p->x, "error")) != NULL) {
1434 jbd->error_msg = g_strdup_printf(_("Error %s: %s"),
1435 xmlnode_get_attrib(y, "code"), xmlnode_get_data(y));
1436 } else {
1437 jbd->error_msg = g_strdup(_("Unknown Error in presence"));
1438 }
1026 } else { 1439 } else {
1027 if ((y = xmlnode_get_tag(p->x, "show"))) { 1440 if ((y = xmlnode_get_tag(p->x, "show"))) {
1028 show = xmlnode_get_data(y); 1441 show = xmlnode_get_data(y);
1029 if (!show) { 1442 if (!show) {
1030 state = 0; 1443 state = 0;
1040 } else { 1453 } else {
1041 state = 0; 1454 state = 0;
1042 } 1455 }
1043 } 1456 }
1044 1457
1045 who = jid_new(gjc->p, from); 1458 if ((y = xmlnode_get_tag(p->x, "priority")))
1046 if (who->user == NULL) { 1459 priority = atoi(xmlnode_get_data(y));
1047 /* FIXME: transport */
1048 return;
1049 }
1050
1051 buddy = g_strdup_printf("%s@%s", who->user, who->server);
1052 1460
1053 /* um. we're going to check if it's a chat. if it isn't, and there are pending 1461 /* um. we're going to check if it's a chat. if it isn't, and there are pending
1054 * chats, create the chat. if there aren't pending chats and we don't have the 1462 * chats, create the chat. if there aren't pending chats and we don't have the
1055 * buddy on our list, simply bail out. */ 1463 * buddy on our list, simply bail out. */
1056 if ((cnv = find_chat(GJ_GC(gjc), who->user)) == NULL) { 1464 if ((cnv = find_chat(GJ_GC(gjc), gjid->user)) == NULL) {
1057 static int i = 0x70; 1465 static int i = 0x70;
1058 if ((jc = find_pending_chat(GJ_GC(gjc), who)) != NULL) { 1466 if ((jc = find_pending_chat(GJ_GC(gjc), gjid)) != NULL) {
1059 jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, who->user); 1467 jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, gjid->user);
1060 jc->id = jc->b->id; 1468 jc->id = jc->b->id;
1061 jc->state = JCS_ACTIVE; 1469 jc->state = JCS_ACTIVE;
1062 } else if ((b = find_buddy(GJ_GC(gjc), buddy)) == NULL) { 1470 } else if ((b = find_buddy(GJ_GC(gjc), buddy)) == NULL) {
1063 g_free(buddy); 1471 g_free(buddy);
1472 gaim_jid_free(gjid);
1064 return; 1473 return;
1065 } 1474 }
1066 } 1475 }
1067 1476
1477 if (type && (strcasecmp(type, "unavailable") == 0))
1478 jabber_remove_resource(GJ_GC(gjc), buddy, gjid->resource);
1479 else {
1480 jabber_track_resource(GJ_GC(gjc), buddy, gjid->resource, priority, state);
1481
1482 /* keep track of away msg somewhat the same as the yahoo plugin */
1483 jabber_track_away(gjc, p, type);
1484 }
1485
1486
1068 if (!cnv) { 1487 if (!cnv) {
1069 resources = b->proto_data; 1488 /* this is where we handle presence information for "regular" buddies */
1070 res = who->resource; 1489 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), buddy);
1071 if (res) 1490 if(jri) {
1072 while (resources) { 1491 serv_got_update(GJ_GC(gjc), buddy, 1, 0, b->signon, b->idle, jri->state, 0);
1073 if (resources->data && !strcmp(res, resources->data)) 1492 } else
1074 break; 1493 serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0, 0);
1075 resources = resources->next; 1494
1076 }
1077
1078 /* keep track of away msg same as yahoo plugin */
1079 jabber_track_away(gjc, p, normalize(b->name), type);
1080
1081 if (type && (strcasecmp(type, "unavailable") == 0)) {
1082 if (resources) {
1083 g_free(resources->data);
1084 b->proto_data = g_slist_remove(b->proto_data, resources->data);
1085 }
1086 if (!b->proto_data) {
1087 serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0, 0);
1088 }
1089 } else {
1090 if (res && !resources) {
1091 b->proto_data = g_slist_append(b->proto_data, g_strdup(res));
1092 }
1093
1094 serv_got_update(GJ_GC(gjc), buddy, 1, 0, b->signon, b->idle, state, 0);
1095
1096 }
1097 } else { 1495 } else {
1098 if (who->resource) { 1496 if (gjid->resource) {
1099 char *buf;
1100
1101 buf = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource);
1102 jabber_track_away(gjc, p, buf, type);
1103 g_free(buf);
1104
1105 if (type && (!strcasecmp(type, "unavailable"))) { 1497 if (type && (!strcasecmp(type, "unavailable"))) {
1106 struct jabber_data *jd; 1498 struct jabber_data *jd;
1107 if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) { 1499 if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), gjid))) {
1108 g_free(buddy); 1500 g_free(buddy);
1501 gaim_jid_free(gjid);
1109 return; 1502 return;
1110 } 1503 }
1111 jd = jc->gc->proto_data; 1504 jd = jc->gc->proto_data;
1112 /* if it's not ourselves...*/ 1505 /* if it's not ourselves...*/
1113 if (strcmp(who->resource, jc->Jid->resource) && jc->b) { 1506 if (strcmp(gjid->resource, jc->gjid->resource) && jc->b) {
1114 remove_chat_buddy(jc->b, who->resource, NULL); 1507 remove_chat_buddy(jc->b, gjid->resource, NULL);
1115 g_free(buddy); 1508 g_free(buddy);
1509 gaim_jid_free(gjid);
1116 return; 1510 return;
1117 } 1511 }
1118 1512
1119 jc->state = JCS_CLOSED; 1513 jc->state = JCS_CLOSED;
1120 serv_got_chat_left(GJ_GC(gjc), jc->id); 1514 serv_got_chat_left(GJ_GC(gjc), jc->id);
1122 * TBD: put back some day? 1516 * TBD: put back some day?
1123 jd->chats = g_slist_remove(jd->chats, jc); 1517 jd->chats = g_slist_remove(jd->chats, jc);
1124 g_free(jc); 1518 g_free(jc);
1125 */ 1519 */
1126 } else { 1520 } else {
1127 if ((!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) || !jc->b) { 1521 if ((!jc && !(jc = find_existing_chat(GJ_GC(gjc), gjid))) || !jc->b) {
1128 g_free(buddy); 1522 g_free(buddy);
1523 gaim_jid_free(gjid);
1129 return; 1524 return;
1130 } 1525 }
1131 if (!find_chat_buddy(jc->b, who->resource)) { 1526 if (!find_chat_buddy(jc->b, gjid->resource)) {
1132 add_chat_buddy(jc->b, who->resource); 1527 add_chat_buddy(jc->b, gjid->resource);
1133 } 1528 }
1134 } 1529 }
1135 } 1530 }
1136 } 1531 }
1137 1532
1138 g_free(buddy); 1533 g_free(buddy);
1534 gaim_jid_free(gjid);
1139 1535
1140 return; 1536 return;
1141 } 1537 }
1142 1538
1143 /* 1539 /*
1279 * Called with roster item node. 1675 * Called with roster item node.
1280 */ 1676 */
1281 static void jabber_handlebuddy(gjconn gjc, xmlnode x) 1677 static void jabber_handlebuddy(gjconn gjc, xmlnode x)
1282 { 1678 {
1283 xmlnode g; 1679 xmlnode g;
1284 char *Jid, *name, *sub, *ask; 1680 char *who, *name, *sub, *ask;
1285 jid who; 1681 gaim_jid gjid;
1286 struct buddy *b = NULL; 1682 struct buddy *b = NULL;
1287 char *buddyname, *groupname = NULL; 1683 char *buddyname, *groupname = NULL;
1288 1684
1289 Jid = xmlnode_get_attrib(x, "jid"); 1685 who = xmlnode_get_attrib(x, "jid");
1290 name = xmlnode_get_attrib(x, "name"); 1686 name = xmlnode_get_attrib(x, "name");
1291 sub = xmlnode_get_attrib(x, "subscription"); 1687 sub = xmlnode_get_attrib(x, "subscription");
1292 ask = xmlnode_get_attrib(x, "ask"); 1688 ask = xmlnode_get_attrib(x, "ask");
1293 who = jid_new(gjc->p, Jid); 1689
1690 if((buddyname = get_realwho(gjc, who, FALSE, &gjid)) == NULL)
1691 return;
1294 1692
1295 /* JFIXME: jabber_handleroster() had a "FIXME: transport" at this 1693 /* JFIXME: jabber_handleroster() had a "FIXME: transport" at this
1296 * equivilent point. So... 1694 * equivilent point. So...
1297 * 1695 *
1298 * We haven't allocated any memory or done anything interesting to 1696 * We haven't done anything interesting to this point, so we'll
1299 * this point, so we'll violate Good Coding Structure here by 1697 * violate Good Coding Structure here by simply bailing out.
1300 * simply bailing out.
1301 */ 1698 */
1302 if (!who || !who->user) { 1699 if(!gjid->user) {
1700 g_free(buddyname);
1701 gaim_jid_free(gjid);
1303 return; 1702 return;
1304 } 1703 }
1305 1704 gaim_jid_free(gjid);
1306 buddyname = g_strdup_printf("%s@%s", who->user, who->server);
1307 1705
1308 if((g = xmlnode_get_tag(x, "group")) != NULL) { 1706 if((g = xmlnode_get_tag(x, "group")) != NULL) {
1309 groupname = xmlnode_get_data(g); 1707 groupname = xmlnode_get_data(g);
1310 } 1708 }
1311 1709
1336 remove_buddy(GJ_GC(gjc), c_grp, b); 1734 remove_buddy(GJ_GC(gjc), c_grp, b);
1337 b = add_buddy(GJ_GC(gjc), groupname, buddyname, 1735 b = add_buddy(GJ_GC(gjc), groupname, buddyname,
1338 name ? name : buddyname); 1736 name ? name : buddyname);
1339 do_export(GJ_GC(gjc)); 1737 do_export(GJ_GC(gjc));
1340 if(present) { 1738 if(present) {
1341 serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle, uc, 0); 1739 serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle,
1740 uc, 0);
1342 } 1741 }
1343 } else if(name != NULL && strcmp(b->show, name)) { 1742 } else if(name != NULL && strcmp(b->show, name)) {
1344 strncpy(b->show, name, BUDDY_ALIAS_MAXLEN); 1743 strncpy(b->show, name, BUDDY_ALIAS_MAXLEN);
1345 b->show[BUDDY_ALIAS_MAXLEN - 1] = '\0'; /* cheap safety feature */ 1744 b->show[BUDDY_ALIAS_MAXLEN - 1] = '\0'; /* cheap safety feature */
1346 handle_buddy_rename(b, buddyname); 1745 handle_buddy_rename(b, buddyname);
1599 * way the user always gets some kind of response. 1998 * way the user always gets some kind of response.
1600 */ 1999 */
1601 jabber_handlevcard(gjc, NULL, from); 2000 jabber_handlevcard(gjc, NULL, from);
1602 } else if(!strcmp((char *) val, "change_password")) { 2001 } else if(!strcmp((char *) val, "change_password")) {
1603 char buf[BUF_LONG]; 2002 char buf[BUF_LONG];
1604 sprintf(buf,_("Password successfully changed.")); 2003 sprintf(buf, _("Password successfully changed."));
1605 2004
1606 do_error_dialog(buf, _("Password Change")); 2005 do_error_dialog(buf, _("Password Change"));
1607 } 2006 }
1608 } 2007 }
1609 } 2008 }
1669 { 2068 {
1670 struct gaim_connection *gc = new_gaim_conn(user); 2069 struct gaim_connection *gc = new_gaim_conn(user);
1671 struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); 2070 struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1);
1672 char *loginname = create_valid_jid(user->username, DEFAULT_SERVER, "GAIM"); 2071 char *loginname = create_valid_jid(user->username, DEFAULT_SERVER, "GAIM");
1673 2072
1674 jd->hash = g_hash_table_new(g_str_hash, g_str_equal); 2073 jd->buddies = g_hash_table_new(g_str_hash, g_str_equal);
1675 jd->chats = NULL; /* we have no chats yet */ 2074 jd->chats = NULL; /* we have no chats yet */
1676 2075
1677 set_login_progress(gc, 1, _("Connecting")); 2076 set_login_progress(gc, 1, _("Connecting"));
1678 2077
1679 if (!(jd->gjc = gjab_new(loginname, user->password, gc))) { 2078 if (!(jd->gjc = gjab_new(loginname, user->password, gc))) {
1695 g_free(key); 2094 g_free(key);
1696 g_free(val); 2095 g_free(val);
1697 return TRUE; 2096 return TRUE;
1698 } 2097 }
1699 2098
2099 static gboolean jabber_destroy_buddy_hash(gpointer key, gpointer val, gpointer data) {
2100 struct jabber_buddy_data *jbd = val;
2101 while (jbd->resources) {
2102 g_free(((jab_res_info) ((GSList *)jbd->resources)->data)->name);
2103 if(((jab_res_info) ((GSList *)jbd->resources)->data)->away_msg)
2104 g_free(((jab_res_info) ((GSList *)jbd->resources)->data)->away_msg);
2105 g_free(((GSList *)jbd->resources)->data);
2106 jbd->resources = g_slist_remove(jbd->resources, ((GSList *)jbd->resources)->data);
2107
2108 }
2109 if(jbd->error_msg)
2110 g_free(jbd->error_msg);
2111 g_free(key);
2112 g_free(jbd);
2113 return TRUE;
2114 }
2115
2116
1700 static gboolean jabber_free(gpointer data) 2117 static gboolean jabber_free(gpointer data)
1701 { 2118 {
1702 struct jabber_data *jd = data; 2119 struct jabber_data *jd = data;
1703 2120
1704 if(jd->gjc != NULL) { 2121 if(jd->gjc != NULL) {
1718 if(jd) { 2135 if(jd) {
1719 GSList *jcs = jd->chats; 2136 GSList *jcs = jd->chats;
1720 2137
1721 /* Free-up the jabber_chat struct allocs and the list */ 2138 /* Free-up the jabber_chat struct allocs and the list */
1722 while (jcs) { 2139 while (jcs) {
2140 gaim_jid_free(((struct jabber_chat *)jcs->data)->gjid);
1723 g_free(jcs->data); 2141 g_free(jcs->data);
1724 jcs = jcs->next; 2142 jcs = jcs->next;
1725 } 2143 }
1726 g_slist_free(jd->chats); 2144 g_slist_free(jd->chats);
1727 2145
1728 /* Free-up the away status memories and the list */ 2146 /* Free-up the buddy data hash */
1729 if(jd->hash != NULL) { 2147 if(jd->buddies != NULL)
1730 g_hash_table_foreach_remove(jd->hash, jabber_destroy_hash, NULL); 2148 {
1731 g_hash_table_destroy(jd->hash); 2149 g_hash_table_foreach_remove(jd->buddies, jabber_destroy_buddy_hash, NULL);
1732 jd->hash = NULL; 2150 g_hash_table_destroy(jd->buddies);
2151 jd->buddies = NULL;
1733 } 2152 }
1734 2153
1735 /* Free-up the pending queries memories and the list */ 2154 /* Free-up the pending queries memories and the list */
1736 if(jd->gjc != NULL && jd->gjc->queries != NULL) { 2155 if(jd->gjc != NULL && jd->gjc->queries != NULL) {
1737 g_hash_table_foreach_remove(jd->gjc->queries, jabber_destroy_hash, NULL); 2156 g_hash_table_foreach_remove(jd->gjc->queries, jabber_destroy_hash, NULL);
1748 xmlnode_free(jd->gjc->current); 2167 xmlnode_free(jd->gjc->current);
1749 } 2168 }
1750 gc->proto_data = NULL; 2169 gc->proto_data = NULL;
1751 } 2170 }
1752 2171
1753 static int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags) 2172 static int jabber_send_typing(struct gaim_connection *gc, char *who, int typing)
1754 { 2173 {
1755 xmlnode x, y; 2174 xmlnode x, y;
1756 char *realwho; 2175 char *realwho;
1757 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; 2176 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
2177 jab_res_info jri = jabber_find_resource(gc, who);
2178
2179 if(!jri || !jri->has_composing)
2180 return 0;
2181
2182 if((realwho = get_realwho(gjc, who, FALSE, NULL)) == NULL)
2183 return 0;
2184
2185 x = xmlnode_new_tag("message");
2186 xmlnode_put_attrib(x, "to", realwho);
2187 xmlnode_insert_tag(x, "gaim");
2188
2189 y = xmlnode_insert_tag(x, "x");
2190 xmlnode_put_attrib(y, "xmlns", "jabber:x:event");
2191
2192 if(typing)
2193 xmlnode_insert_tag(y, "composing");
2194
2195 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
2196 xmlnode_free(x);
2197 g_free(realwho);
2198 return JABBER_TYPING_NOTIFY_INT;
2199 }
2200
2201 static int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags)
2202 {
2203 xmlnode x, y;
2204 char *realwho;
2205 char *thread_id = NULL;
2206 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
1758 2207
1759 if (!who || !message) 2208 if (!who || !message)
1760 return 0; 2209 return 0;
1761 2210
2211 if((realwho = get_realwho(gjc, who, FALSE, NULL)) == NULL)
2212 return 0;
2213
1762 x = xmlnode_new_tag("message"); 2214 x = xmlnode_new_tag("message");
1763 /* Bare username and "username" not the server itself? */
1764 if (!strchr(who, '@') && strcmp(who, gjc->user->server) != 0)
1765 realwho = g_strdup_printf("%s@%s", who, gjc->user->server);
1766 else
1767 realwho = g_strdup(who);
1768 xmlnode_put_attrib(x, "to", realwho); 2215 xmlnode_put_attrib(x, "to", realwho);
2216
2217 thread_id = jabber_get_convo_thread(gjc, realwho);
2218 if(thread_id)
2219 {
2220 y = xmlnode_insert_tag(x, "thread");
2221 xmlnode_insert_cdata(y, thread_id, -1);
2222 g_free(thread_id);
2223 }
2224
1769 g_free(realwho); 2225 g_free(realwho);
1770 2226
1771 xmlnode_insert_tag(x, "gaim"); 2227 xmlnode_insert_tag(x, "gaim");
1772 xmlnode_put_attrib(x, "type", "chat"); 2228 xmlnode_put_attrib(x, "type", "chat");
2229
2230 /* let other clients know we support typing notification */
2231 y = xmlnode_insert_tag(x, "x");
2232 xmlnode_put_attrib(y, "xmlns", "jabber:x:event");
2233 xmlnode_insert_tag(y, "composing");
1773 2234
1774 if (message && strlen(message)) { 2235 if (message && strlen(message)) {
1775 char *utf8 = str_to_utf8(message); 2236 char *utf8 = str_to_utf8(message);
1776 y = xmlnode_insert_tag(x, "body"); 2237 y = xmlnode_insert_tag(x, "body");
1777 xmlnode_insert_cdata(y, utf8, -1); 2238 xmlnode_insert_cdata(y, utf8, -1);
1793 gjconn gjc; 2254 gjconn gjc;
1794 struct buddy *buddy = NULL; 2255 struct buddy *buddy = NULL;
1795 struct group *buddy_group = NULL; 2256 struct group *buddy_group = NULL;
1796 2257
1797 if(gc && gc->proto_data && ((struct jabber_data *)gc->proto_data)->gjc && name) { 2258 if(gc && gc->proto_data && ((struct jabber_data *)gc->proto_data)->gjc && name) {
2259 gaim_jid gjid;
1798 gjc = ((struct jabber_data *)gc->proto_data)->gjc; 2260 gjc = ((struct jabber_data *)gc->proto_data)->gjc;
1799 2261
1800 if (!strchr(name, '@')) 2262 if((realwho = get_realwho(gjc, name, FALSE, &gjid)) == NULL)
1801 realwho = g_strdup_printf("%s@%s", name, gjc->user->server); 2263 return;
1802 else { 2264
1803 jid who = jid_new(gjc->p, name); 2265 /* FIXME: transport */
1804 if (who->user == NULL) { 2266 if(gjid->user == NULL) {
1805 /* FIXME: transport */ 2267 g_free(realwho);
1806 return; 2268 gaim_jid_free(gjid);
1807 } 2269 return;
1808 realwho = g_strdup_printf("%s@%s", who->user, who->server); 2270 }
1809 } 2271 gaim_jid_free(gjid);
1810
1811 2272
1812 x = jutil_iqnew(JPACKET__SET, NS_ROSTER); 2273 x = jutil_iqnew(JPACKET__SET, NS_ROSTER);
1813 y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); 2274 y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item");
1814 xmlnode_put_attrib(y, "jid", realwho); 2275 xmlnode_put_attrib(y, "jid", realwho);
1815 2276
1816 2277
1817 /* If we can find the buddy, there's an alias for him, it's not 0-length 2278 /* If we can find the buddy, there's an alias for him, it's not 0-length
1818 * and it doesn't match his JID, add the "name" attribute. 2279 * and it doesn't match his JID, add the "name" attribute.
1819 */ 2280 */
1820 if((buddy = find_buddy(gc, realwho)) != NULL && 2281 if((buddy = find_buddy(gc, realwho)) != NULL &&
1821 buddy->show != NULL && buddy->show[0] != '\0' && strcmp(realwho, buddy->show)) { 2282 buddy->show != NULL && buddy->show[0] != '\0' && strcmp(realwho, buddy->show))
1822 2283 {
1823 xmlnode_put_attrib(y, "name", buddy->show); 2284 char *utf8 = str_to_utf8(buddy->show);
2285 xmlnode_put_attrib(y, "name", utf8);
2286 g_free(utf8);
1824 } 2287 }
1825 2288
1826 /* 2289 /*
1827 * Find out what group the buddy's in and send that along 2290 * Find out what group the buddy's in and send that along
1828 * with the roster item. 2291 * with the roster item.
1853 static void jabber_add_buddy(struct gaim_connection *gc, char *name) 2316 static void jabber_add_buddy(struct gaim_connection *gc, char *name)
1854 { 2317 {
1855 xmlnode x; 2318 xmlnode x;
1856 char *realwho; 2319 char *realwho;
1857 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; 2320 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
2321 gaim_jid gjid;
1858 2322
1859 if (!((struct jabber_data *)gc->proto_data)->did_import) 2323 if (!((struct jabber_data *)gc->proto_data)->did_import)
1860 return; 2324 return;
1861 2325
1862 if (!name) 2326 /*
2327 * If there's no name or the name is ourself
2328 */
2329 if(!name || !strcmp(gc->username, name))
1863 return; 2330 return;
1864 2331
1865 if (!strcmp(gc->username, name)) 2332 if((realwho = get_realwho(gjc, name, FALSE, &gjid)) == NULL) {
2333 char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), name);
2334 do_error_dialog(msg, _("Jabber Error"));
2335 g_free(msg);
2336 jabber_remove_gaim_buddy(gc, name);
1866 return; 2337 return;
1867 2338 }
1868 if (!strchr(name, '@')) 2339
1869 realwho = g_strdup_printf("%s@%s", name, gjc->user->server); 2340 /* FIXME: transport */
1870 else { 2341 if(gjid->user == NULL) {
1871 jid who; 2342 g_free(realwho);
1872 2343 gaim_jid_free(gjid);
1873 if((who = jid_new(gjc->p, name)) == NULL) { 2344 return;
1874 char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), name); 2345 }
1875 do_error_dialog(msg, _("Jabber Error")); 2346 gaim_jid_free(gjid);
1876 g_free(msg);
1877 jabber_remove_gaim_buddy(gc, name);
1878 return;
1879 }
1880 if (who->user == NULL) {
1881 /* FIXME: transport */
1882 return;
1883 }
1884 realwho = g_strdup_printf("%s@%s", who->user, who->server);
1885 }
1886 2347
1887 x = xmlnode_new_tag("presence"); 2348 x = xmlnode_new_tag("presence");
1888 xmlnode_put_attrib(x, "to", realwho); 2349 xmlnode_put_attrib(x, "to", realwho);
1889 xmlnode_put_attrib(x, "type", "subscribe"); 2350 xmlnode_put_attrib(x, "type", "subscribe");
1890 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); 2351 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
1899 { 2360 {
1900 xmlnode x; 2361 xmlnode x;
1901 char *realwho; 2362 char *realwho;
1902 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; 2363 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
1903 2364
1904 if (!name) 2365 if(!name || (realwho = get_realwho(gjc, name, FALSE, NULL)) == NULL)
1905 return; 2366 return;
1906
1907 if (!strchr(name, '@'))
1908 realwho = g_strdup_printf("%s@%s", name, gjc->user->server);
1909 else
1910 realwho = g_strdup(name);
1911 2367
1912 x = xmlnode_new_tag("presence"); 2368 x = xmlnode_new_tag("presence");
1913 xmlnode_put_attrib(x, "to", realwho); 2369 xmlnode_put_attrib(x, "to", realwho);
1914 xmlnode_put_attrib(x, "type", "unsubscribe"); 2370 xmlnode_put_attrib(x, "type", "unsubscribe");
1915 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); 2371 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
2007 xmlnode x; 2463 xmlnode x;
2008 char *realwho; 2464 char *realwho;
2009 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; 2465 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
2010 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; 2466 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats;
2011 struct jabber_chat *jc; 2467 struct jabber_chat *jc;
2012 jid Jid; 2468 gaim_jid gjid;
2013 2469
2014 if (!data || !data->next || !data->next->next) 2470 if (!data || !data->next || !data->next->next)
2015 return; 2471 return;
2016 2472
2017 realwho = create_valid_jid(data->data, data->next->data, 2473 realwho = create_valid_jid(data->data, data->next->data, data->next->next->data);
2018 data->next->next->data);
2019 debug_printf("%s\n", realwho); 2474 debug_printf("%s\n", realwho);
2020 2475
2021 if((Jid = jid_new(gjc->p, realwho)) == NULL) { 2476 if((gjid = gaim_jid_new(realwho)) == NULL) {
2022 char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), realwho); 2477 char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), realwho);
2023 do_error_dialog(msg, _("Jabber Error")); 2478 do_error_dialog(msg, _("Jabber Error"));
2024 g_free(msg); 2479 g_free(msg);
2480 g_free(realwho);
2025 return; 2481 return;
2026 } 2482 }
2027 2483
2028 if((jc = find_any_chat(gc, Jid)) != NULL) { 2484 if((jc = find_any_chat(gc, gjid)) != NULL) {
2029 free(Jid); /* don't need it, after all */
2030 switch(jc->state) { 2485 switch(jc->state) {
2031 case JCS_PENDING: 2486 case JCS_PENDING:
2032 debug_printf("attempt to re-join already pending Jabber chat! (ignoring)\n"); 2487 debug_printf("attempt to re-join already pending Jabber chat! (ignoring)\n");
2033 g_free(realwho); /* yuck! */ 2488 g_free(realwho); /* yuck! */
2489 gaim_jid_free(gjid);
2034 return; 2490 return;
2035 case JCS_ACTIVE: 2491 case JCS_ACTIVE:
2036 debug_printf("attempt to re-join already active Jabber chat! (ignoring)\n"); 2492 debug_printf("attempt to re-join already active Jabber chat! (ignoring)\n");
2037 g_free(realwho); /* yuck! */ 2493 g_free(realwho); /* yuck! */
2494 gaim_jid_free(gjid);
2038 return; 2495 return;
2039 case JCS_CLOSED: 2496 case JCS_CLOSED:
2040 debug_printf("rejoining previously closed Jabber chat\n"); 2497 debug_printf("rejoining previously closed Jabber chat\n");
2041 break; 2498 break;
2042 default: 2499 default:
2043 debug_printf("found Jabber chat in unknown state! (ignoring)\n"); 2500 debug_printf("found Jabber chat in unknown state! (ignoring)\n");
2044 g_free(realwho); /* yuck! */ 2501 g_free(realwho); /* yuck! */
2502 gaim_jid_free(gjid);
2045 return; 2503 return;
2046 } 2504 }
2047 } else { 2505 } else {
2048 debug_printf("joining completely new Jabber chat\n"); 2506 debug_printf("joining completely new Jabber chat\n");
2049 jc = g_new0(struct jabber_chat, 1); 2507 jc = g_new0(struct jabber_chat, 1);
2050 jc->Jid = Jid; 2508 jc->gjid = gjid;
2051 jc->gc = gc; 2509 jc->gc = gc;
2052 ((struct jabber_data *)gc->proto_data)->chats = g_slist_append(jcs, jc); 2510 ((struct jabber_data *)gc->proto_data)->chats = g_slist_append(jcs, jc);
2511 add_buddy(gc, _("Chats"), realwho, realwho);
2053 } 2512 }
2054 2513
2055 jc->state = JCS_PENDING; 2514 jc->state = JCS_PENDING;
2056 2515
2057 x = jutil_presnew(0, realwho, NULL); 2516 x = jutil_presnew(0, realwho, NULL);
2066 struct jabber_data *jd = gc->proto_data; 2525 struct jabber_data *jd = gc->proto_data;
2067 gjconn gjc = jd->gjc; 2526 gjconn gjc = jd->gjc;
2068 struct jabber_chat *jc = NULL; 2527 struct jabber_chat *jc = NULL;
2069 char *realwho, *subject; 2528 char *realwho, *subject;
2070 2529
2071 if (!name) 2530 if(!name || (realwho = get_realwho(gjc, name, FALSE, NULL)) == NULL)
2072 return; 2531 return;
2073 2532
2074 /* find which chat we're inviting to */ 2533 /* find which chat we're inviting to */
2075 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) 2534 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0)
2076 return; 2535 return;
2077 2536
2078 x = xmlnode_new_tag("message"); 2537 x = xmlnode_new_tag("message");
2079 if (!strchr(name, '@'))
2080 realwho = g_strdup_printf("%s@%s", name, gjc->user->server);
2081 else
2082 realwho = g_strdup(name);
2083 xmlnode_put_attrib(x, "to", realwho); 2538 xmlnode_put_attrib(x, "to", realwho);
2539
2084 g_free(realwho); 2540 g_free(realwho);
2085 2541
2086 y = xmlnode_insert_tag(x, "x"); 2542 y = xmlnode_insert_tag(x, "x");
2087 xmlnode_put_attrib(y, "xmlns", "jabber:x:conference"); 2543 xmlnode_put_attrib(y, "xmlns", "jabber:x:conference");
2088 subject = g_strdup_printf("%s@%s", jc->Jid->user, jc->Jid->server); 2544 subject = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server);
2089 xmlnode_put_attrib(y, "jid", subject); 2545 xmlnode_put_attrib(y, "jid", subject);
2090 g_free(subject); 2546 g_free(subject);
2091 2547
2092 if (message && strlen(message)) { 2548 if (message && strlen(message)) {
2093 char *utf8 = str_to_utf8(message); 2549 char *utf8 = str_to_utf8(message);
2103 static void jabber_chat_leave(struct gaim_connection *gc, int id) 2559 static void jabber_chat_leave(struct gaim_connection *gc, int id)
2104 { 2560 {
2105 struct jabber_data *jd = gc->proto_data; 2561 struct jabber_data *jd = gc->proto_data;
2106 gjconn gjc = jd->gjc; 2562 gjconn gjc = jd->gjc;
2107 struct jabber_chat *jc = NULL; 2563 struct jabber_chat *jc = NULL;
2108 char *realwho; 2564 char *chatname;
2109 xmlnode x; 2565 xmlnode x;
2110 2566
2111 /* Find out which chat we're leaving */ 2567 /* Find out which chat we're leaving */
2112 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) 2568 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0)
2113 return; 2569 return;
2114 2570
2115 realwho = g_strdup_printf("%s@%s", jc->Jid->user, jc->Jid->server); 2571 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server);
2116 x = jutil_presnew(0, realwho, NULL); 2572 x = jutil_presnew(0, chatname, NULL);
2117 g_free(realwho); 2573 g_free(chatname);
2118 xmlnode_put_attrib(x, "type", "unavailable"); 2574 xmlnode_put_attrib(x, "type", "unavailable");
2119 gjab_send(gjc, x); 2575 gjab_send(gjc, x);
2120 xmlnode_free(x); 2576 xmlnode_free(x);
2121 jc->b = NULL; 2577 jc->b = NULL;
2122 } 2578 }
2131 /* Find out which chat we're sending to */ 2587 /* Find out which chat we're sending to */
2132 if((retval = jabber_find_chat_by_convo_id(gc, id, &jc)) != 0) 2588 if((retval = jabber_find_chat_by_convo_id(gc, id, &jc)) != 0)
2133 return(retval); 2589 return(retval);
2134 2590
2135 x = xmlnode_new_tag("message"); 2591 x = xmlnode_new_tag("message");
2136 xmlnode_put_attrib(x, "from", jid_full(jc->Jid)); 2592 xmlnode_put_attrib(x, "from", jc->gjid->full);
2137 chatname = g_strdup_printf("%s@%s", jc->Jid->user, jc->Jid->server); 2593 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server);
2138 xmlnode_put_attrib(x, "to", chatname); 2594 xmlnode_put_attrib(x, "to", chatname);
2139 g_free(chatname); 2595 g_free(chatname);
2140 xmlnode_put_attrib(x, "type", "groupchat"); 2596 xmlnode_put_attrib(x, "type", "groupchat");
2141 2597
2142 if (message && strlen(message) > strlen("/topic ") && 2598 if (message && strlen(message) > strlen("/topic ") &&
2170 /* Find out which chat we're whispering to */ 2626 /* Find out which chat we're whispering to */
2171 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) 2627 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0)
2172 return; 2628 return;
2173 2629
2174 x = xmlnode_new_tag("message"); 2630 x = xmlnode_new_tag("message");
2175 xmlnode_put_attrib(x, "from", jid_full(jc->Jid)); 2631 xmlnode_put_attrib(x, "from", jc->gjid->full);
2176 chatname = g_strdup_printf("%s@%s/%s", jc->Jid->user, jc->Jid->server, who); 2632 chatname = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who);
2177 xmlnode_put_attrib(x, "to", chatname); 2633 xmlnode_put_attrib(x, "to", chatname);
2178 g_free(chatname); 2634 g_free(chatname);
2179 xmlnode_put_attrib(x, "type", "normal"); 2635 xmlnode_put_attrib(x, "type", "normal");
2180 2636
2181 if (message && strlen(message)) { 2637 if (message && strlen(message)) {
2228 char *id; 2684 char *id;
2229 char *realwho; 2685 char *realwho;
2230 struct jabber_data *jd = gc->proto_data; 2686 struct jabber_data *jd = gc->proto_data;
2231 gjconn gjc = jd->gjc; 2687 gjconn gjc = jd->gjc;
2232 2688
2689 if((realwho = get_realwho(gjc, who, TRUE, NULL)) == NULL)
2690 return;
2691
2233 x = jutil_iqnew(JPACKET__GET, NS_VCARD); 2692 x = jutil_iqnew(JPACKET__GET, NS_VCARD);
2234 /* Bare username? */
2235 if (!strchr(who, '@')) {
2236 realwho = g_strdup_printf("%s@%s", who, gjc->user->server);
2237 } else {
2238 realwho = g_strdup(who);
2239 }
2240 xmlnode_put_attrib(x, "to", realwho); 2693 xmlnode_put_attrib(x, "to", realwho);
2694
2241 g_free(realwho); 2695 g_free(realwho);
2242 2696
2243 id = gjab_getid(gjc); 2697 id = gjab_getid(gjc);
2244 xmlnode_put_attrib(x, "id", id); 2698 xmlnode_put_attrib(x, "id", id);
2245 2699
2246 g_hash_table_insert(jd->gjc->queries, g_strdup(id), g_strdup("vCard")); 2700 g_hash_table_insert(jd->gjc->queries, g_strdup(id), g_strdup("vCard"));
2247 2701
2248 gjab_send(gjc, x); 2702 gjab_send(gjc, x);
2249 2703
2250 xmlnode_free(x); 2704 xmlnode_free(x);
2705 }
2706
2707 static void jabber_get_error_msg(struct gaim_connection *gc, char *who) {
2708 struct jabber_data *jd = gc->proto_data;
2709 gjconn gjc = jd->gjc;
2710 gchar **str_arr = (gchar **) g_new(gpointer, 3);
2711 gchar **ap = str_arr;
2712 gchar *realwho, *final;
2713 struct jabber_buddy_data *jbd;
2714
2715 if((realwho = get_realwho(gjc, who, FALSE, NULL)) == NULL) {
2716 g_strfreev(str_arr);
2717 return;
2718 }
2719
2720 jbd = jabber_find_buddy(gc, realwho);
2721
2722 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho);
2723 *ap++ = g_strdup_printf("<B>Error:</B> %s<BR>\n", jbd->error_msg);
2724 *ap = NULL;
2251 2725
2726 final= g_strjoinv(NULL, str_arr);
2727
2728 g_strfreev(str_arr);
2729
2730 g_show_info_text(gc, realwho, 2, final, NULL);
2731 g_free(realwho);
2732 g_free(final);
2252 } 2733 }
2253 2734
2254 static void jabber_get_away_msg(struct gaim_connection *gc, char *who) { 2735 static void jabber_get_away_msg(struct gaim_connection *gc, char *who) {
2255 struct jabber_data *jd = gc->proto_data; 2736 struct jabber_data *jd = gc->proto_data;
2256 gjconn gjc = jd->gjc; 2737 gjconn gjc = jd->gjc;
2257 char *status; 2738 int num_resources;
2739 gaim_jid gjid;
2740 char *buddy = get_realwho(gjc, who, FALSE, &gjid);
2741 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy);
2742 gchar **str_arr;
2743 gchar **ap;
2744 gchar *realwho, *final;
2745 GSList *resources;
2746 int i;
2747
2748 if(!buddy)
2749 return;
2750
2751 if(!gjid->resource) {
2752 num_resources = g_slist_length(jbd->resources);
2753 resources = jbd->resources;
2754 } else {
2755 num_resources = 1;
2756 resources = jbd->resources;
2757 while(strcasecmp(((jab_res_info)resources->data)->name, gjid->resource))
2758 resources = resources->next;
2759 }
2760
2761 gaim_jid_free(gjid);
2258 2762
2259 /* space for all elements: Jabber I.D. + "status" + NULL (list terminator) */ 2763 /* space for all elements: Jabber I.D. + "status" + NULL (list terminator) */
2260 gchar **str_arr = (gchar **) g_new(gpointer, 3); 2764 str_arr = (gchar **) g_new(gpointer, num_resources*2 + 1);
2261 gchar **ap = str_arr; 2765 ap = str_arr;
2262 gchar *realwho, *final; 2766
2263 2767 for(i=0; i<num_resources; i++)
2264 /* Bare username? */ 2768 {
2265 if (!strchr(who, '@')) { 2769 jab_res_info jri = resources->data;
2266 realwho = g_strdup_printf("%s@%s", who, gjc->user->server); 2770 realwho = g_strdup_printf("%s/%s", buddy, jri->name);
2267 } else { 2771 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho);
2268 realwho = g_strdup(who); 2772 *ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", jabber_lookup_away(gjc, realwho));
2269 } 2773 g_free(realwho);
2270 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho); 2774 resources = resources->next;
2271 2775 }
2272 if((status = g_hash_table_lookup(jd->hash, realwho)) == NULL) {
2273 status = _("Unknown");
2274 }
2275 *ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", status);
2276 2776
2277 *ap = NULL; 2777 *ap = NULL;
2778
2779 g_free(buddy);
2278 2780
2279 final= g_strjoinv(NULL, str_arr); 2781 final= g_strjoinv(NULL, str_arr);
2280 g_strfreev(str_arr); 2782 g_strfreev(str_arr);
2281 2783
2282 g_show_info_text(gc, realwho, 2, final, NULL); 2784 g_show_info_text(gc, who, 2, final, NULL);
2283 g_free(realwho);
2284 g_free(final); 2785 g_free(final);
2285 2786
2286 } 2787 }
2287 2788
2288 static void jabber_get_cb_info(struct gaim_connection *gc, int cid, char *who) { 2789 static void jabber_get_cb_info(struct gaim_connection *gc, int cid, char *who) {
2291 2792
2292 /* Find out which chat */ 2793 /* Find out which chat */
2293 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0) 2794 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0)
2294 return; 2795 return;
2295 2796
2296 realwho = g_strdup_printf("%s@%s/%s", jc->Jid->user, jc->Jid->server, who); 2797 realwho = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who);
2297 2798
2298 jabber_get_info(gc, realwho); 2799 jabber_get_info(gc, realwho);
2299 g_free(realwho); 2800 g_free(realwho);
2300 } 2801 }
2301 2802
2305 2806
2306 /* Find out which chat */ 2807 /* Find out which chat */
2307 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0) 2808 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0)
2308 return; 2809 return;
2309 2810
2310 realwho = g_strdup_printf("%s@%s/%s", jc->Jid->user, jc->Jid->server, who); 2811 realwho = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who);
2311 2812
2312 jabber_get_away_msg(gc, realwho); 2813 jabber_get_away_msg(gc, realwho);
2313
2314 g_free(realwho); 2814 g_free(realwho);
2315 2815
2316 } 2816 }
2317 2817
2318 static GList *jabber_buddy_menu(struct gaim_connection *gc, char *who) { 2818 static GList *jabber_buddy_menu(struct gaim_connection *gc, char *who) {
2319 GList *m = NULL; 2819 GList *m = NULL;
2320 struct proto_buddy_menu *pbm; 2820 struct proto_buddy_menu *pbm;
2321 2821 struct buddy *b = find_buddy(gc, who);
2322 pbm = g_new0(struct proto_buddy_menu, 1); 2822
2323 pbm->label = _("Get Info"); 2823 if(b->uc == UC_ERROR)
2324 pbm->callback = jabber_get_info; 2824 {
2325 pbm->gc = gc; 2825 pbm = g_new0(struct proto_buddy_menu, 1);
2326 m = g_list_append(m, pbm); 2826 pbm->label = _("View Error Msg");
2327 pbm = g_new0(struct proto_buddy_menu, 1); 2827 pbm->callback = jabber_get_error_msg;
2328 pbm->label = _("Get Away Msg"); 2828 pbm->gc = gc;
2329 pbm->callback = jabber_get_away_msg; 2829 m = g_list_append(m, pbm);
2330 pbm->gc = gc; 2830 } else {
2331 m = g_list_append(m, pbm); 2831 pbm = g_new0(struct proto_buddy_menu, 1);
2832 pbm->label = _("Get Info");
2833 pbm->callback = jabber_get_info;
2834 pbm->gc = gc;
2835 m = g_list_append(m, pbm);
2836 pbm = g_new0(struct proto_buddy_menu, 1);
2837 pbm->label = _("Get Away Msg");
2838 pbm->callback = jabber_get_away_msg;
2839 pbm->gc = gc;
2840 m = g_list_append(m, pbm);
2841 }
2332 2842
2333 return m; 2843 return m;
2334 } 2844 }
2335 2845
2336 static GList *jabber_away_states(struct gaim_connection *gc) { 2846 static GList *jabber_away_states(struct gaim_connection *gc) {
2348 static void jabber_set_away(struct gaim_connection *gc, char *state, char *message) 2858 static void jabber_set_away(struct gaim_connection *gc, char *state, char *message)
2349 { 2859 {
2350 xmlnode x, y; 2860 xmlnode x, y;
2351 struct jabber_data *jd = gc->proto_data; 2861 struct jabber_data *jd = gc->proto_data;
2352 gjconn gjc = jd->gjc; 2862 gjconn gjc = jd->gjc;
2863 GSList *jcs;
2864 struct jabber_chat *jc;
2865 char *chatname;
2353 2866
2354 gc->away = NULL; /* never send an auto-response */ 2867 gc->away = NULL; /* never send an auto-response */
2355 2868
2356 x = xmlnode_new_tag("presence"); 2869 x = xmlnode_new_tag("presence");
2357 2870
2388 xmlnode_insert_cdata(y, "dnd", -1); 2901 xmlnode_insert_cdata(y, "dnd", -1);
2389 gc->away = ""; 2902 gc->away = "";
2390 } 2903 }
2391 } 2904 }
2392 2905
2393 gjab_send(gjc, x); 2906 gjab_send(gjc, x); /* Notify "individuals" */
2907
2908 /*
2909 * As of jabberd-1.4.2: simply sending presence to the server doesn't result in
2910 * it being propagated to conference rooms. So we wade thru the list of chats,
2911 * sending our new presence status to each and every one.
2912 */
2913 for(jcs = jd->chats; jcs; jcs = jcs->next) {
2914 jc = jcs->data;
2915 if(jc->state == JCS_ACTIVE) {
2916 xmlnode_put_attrib(x, "from", jc->gjid->full);
2917 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server);
2918 xmlnode_put_attrib(x, "to", chatname);
2919 gjab_send(gjc, x);
2920 g_free(chatname);
2921 }
2922 }
2923
2394 xmlnode_free(x); 2924 xmlnode_free(x);
2395 } 2925 }
2396 2926
2397 static void jabber_set_idle(struct gaim_connection *gc, int idle) { 2927 static void jabber_set_idle(struct gaim_connection *gc, int idle) {
2398 struct jabber_data *jd = (struct jabber_data *)gc->proto_data; 2928 struct jabber_data *jd = (struct jabber_data *)gc->proto_data;
2415 puo->def = "5222"; 2945 puo->def = "5222";
2416 puo->pos = USEROPT_PORT; 2946 puo->pos = USEROPT_PORT;
2417 m = g_list_append(m, puo); 2947 m = g_list_append(m, puo);
2418 2948
2419 return m; 2949 return m;
2420 }
2421
2422 static void jabber_buddy_free(struct buddy *b)
2423 {
2424 while (b->proto_data) {
2425 g_free(((GSList *)b->proto_data)->data);
2426 b->proto_data = g_slist_remove(b->proto_data, ((GSList *)b->proto_data)->data);
2427 }
2428 } 2950 }
2429 2951
2430 /*---------------------------------------*/ 2952 /*---------------------------------------*/
2431 /* Jabber "set info" (vCard) support */ 2953 /* Jabber "set info" (vCard) support */
2432 /*---------------------------------------*/ 2954 /*---------------------------------------*/
2566 * Display a Jabber vCard 3088 * Display a Jabber vCard
2567 */ 3089 */
2568 static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from) 3090 static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from)
2569 { 3091 {
2570 struct gaim_connection *gc = GJ_GC(gjc); 3092 struct gaim_connection *gc = GJ_GC(gjc);
2571 struct jabber_data *jd = GJ_GC(gjc)->proto_data;
2572 jid who = jid_new(gjc->p, from);
2573 char *cdata, *status; 3093 char *cdata, *status;
2574
2575 struct vcard_template *vc_tp = vcard_template_data; 3094 struct vcard_template *vc_tp = vcard_template_data;
2576 3095
2577 /* space for all vCard elements + Jabber I.D. + "status" + NULL (list terminator) */ 3096 /* space for all vCard elements + Jabber I.D. + "status" + NULL (list terminator) */
2578 gchar **str_arr = (gchar **) g_new(gpointer, 3097 gchar **str_arr = (gchar **) g_new(gpointer,
2579 (sizeof(vcard_template_data)/sizeof(struct vcard_template)) + 3); 3098 (sizeof(vcard_template_data)/sizeof(struct vcard_template)) + 3);
2580 gchar **ap = str_arr; 3099 gchar **ap = str_arr;
2581 gchar *buddy, *final; 3100 gchar *buddy, *final;
2582 3101
2583 if(who->resource != NULL && (who->resource)[0] != '\0') { 3102 if((buddy = get_realwho(gjc, from, TRUE, NULL)) == NULL) {
2584 buddy = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource); 3103 g_strfreev(str_arr);
2585 } else { 3104 return;
2586 buddy = g_strdup_printf("%s@%s", who->user, who->server); 3105 }
2587 } 3106
2588 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", buddy); 3107 *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", buddy);
2589 3108
2590 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { 3109 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) {
2591 if(strcmp(vc_tp->tag, "DESC") == 0) 3110 if(strcmp(vc_tp->tag, "DESC") == 0)
2592 continue; /* special handling later */ 3111 continue; /* special handling later */
2606 g_free(fmt); 3125 g_free(fmt);
2607 } 3126 }
2608 } 3127 }
2609 } 3128 }
2610 3129
2611 if((status = g_hash_table_lookup(jd->hash, buddy)) == NULL) { 3130 status = jabber_lookup_away(gjc, buddy);
2612 status = _("Unknown"); 3131
2613 }
2614 *ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", status); 3132 *ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", status);
2615 3133
2616 /* 3134 /*
2617 * "Description" handled as a special case: get a copy of the 3135 * "Description" handled as a special case: get a copy of the
2618 * string and HTML-ize. 3136 * string and HTML-ize.
2801 char *id; 3319 char *id;
2802 struct jabber_data *jd = gc->proto_data; 3320 struct jabber_data *jd = gc->proto_data;
2803 gjconn gjc = jd->gjc; 3321 gjconn gjc = jd->gjc;
2804 3322
2805 x = xmlnode_new_tag("iq"); 3323 x = xmlnode_new_tag("iq");
2806 xmlnode_put_attrib(x,"type","set"); 3324 xmlnode_put_attrib(x, "type", "set");
2807 3325
2808 id = gjab_getid(gjc); 3326 id = gjab_getid(gjc);
2809 3327
2810 xmlnode_put_attrib(x, "id", id); 3328 xmlnode_put_attrib(x, "id", id);
2811 3329
3151 char *loginname = create_valid_jid(au->username, DEFAULT_SERVER, "GAIM"); 3669 char *loginname = create_valid_jid(au->username, DEFAULT_SERVER, "GAIM");
3152 3670
3153 /* 3671 /*
3154 * These do nothing during registration 3672 * These do nothing during registration
3155 */ 3673 */
3156 jd->hash = NULL; 3674 jd->buddies = NULL;
3157 jd->chats = NULL; 3675 jd->chats = NULL;
3158 3676
3159 if ((jd->gjc = gjab_new(loginname, au->password, gc)) == NULL) { 3677 if ((jd->gjc = gjab_new(loginname, au->password, gc)) == NULL) {
3160 g_free(loginname); 3678 g_free(loginname);
3161 debug_printf("jabber: unable to connect (jab_new failed)\n"); 3679 debug_printf("jabber: unable to connect (jab_new failed)\n");
3243 ret->chat_leave = jabber_chat_leave; 3761 ret->chat_leave = jabber_chat_leave;
3244 ret->chat_whisper = jabber_chat_whisper; 3762 ret->chat_whisper = jabber_chat_whisper;
3245 ret->chat_send = jabber_chat_send; 3763 ret->chat_send = jabber_chat_send;
3246 ret->keepalive = jabber_keepalive; 3764 ret->keepalive = jabber_keepalive;
3247 ret->normalize = jabber_normalize; 3765 ret->normalize = jabber_normalize;
3248 ret->buddy_free = jabber_buddy_free;
3249 ret->register_user = jabber_register_user; 3766 ret->register_user = jabber_register_user;
3250 ret->alias_buddy = jabber_roster_update; 3767 ret->alias_buddy = jabber_roster_update;
3251 ret->group_buddy = jabber_group_change; 3768 ret->group_buddy = jabber_group_change;
3769 ret->send_typing = jabber_send_typing;
3770 ret->convo_closed = jabber_convo_closed;
3252 3771
3253 my_protocol = ret; 3772 my_protocol = ret;
3254 } 3773 }
3255 3774
3256 #ifndef STATIC 3775 #ifndef STATIC
3277 { 3796 {
3278 return PRPL_DESC("Jabber"); 3797 return PRPL_DESC("Jabber");
3279 } 3798 }
3280 3799
3281 #endif 3800 #endif
3801
3802 /*
3803 * Local variables:
3804 * c-indentation-style: k&r
3805 * c-basic-offset: 8
3806 * indent-tabs-mode: notnil
3807 * End:
3808 *
3809 * vim: shiftwidth=8:
3810 */