comparison mcabber/src/jabglue.c @ 547:1df26ff0ed8c

Break packethandler() out
author Mikael Berthe <mikael@lilotux.net>
date Sun, 27 Nov 2005 00:19:07 +0100
parents ffdfddd351b8
children 448e299e45da
comparison
equal deleted inserted replaced
546:35f5c8738b55 547:1df26ff0ed8c
69 static void logger(jconn j, int io, const char *buf) 69 static void logger(jconn j, int io, const char *buf)
70 { 70 {
71 scr_LogPrint(LPRINT_DEBUG, "%03s: %s", ((io == 0) ? "OUT" : "IN"), buf); 71 scr_LogPrint(LPRINT_DEBUG, "%03s: %s", ((io == 0) ? "OUT" : "IN"), buf);
72 } 72 }
73 73
74 /*
75 static void jidsplit(const char *jid, char **user, char **host,
76 char **res)
77 {
78 char *tmp, *ptr;
79 tmp = strdup(jid);
80
81 if ((ptr = strchr(tmp, '/')) != NULL) {
82 *res = strdup(ptr+1);
83 *ptr = 0;
84 } else
85 *res = NULL;
86
87 if ((ptr = strchr(tmp, '@')) != NULL) {
88 *host = strdup(ptr+1);
89 *ptr = 0;
90 } else
91 *host = NULL;
92
93 *user = strdup(tmp);
94 free(tmp);
95 }
96 */
97
98 // jidtodisp(jid) 74 // jidtodisp(jid)
99 // Strips the resource part from the jid 75 // Strips the resource part from the jid
100 // The caller should g_free the result after use. 76 // The caller should g_free the result after use.
101 static char *jidtodisp(const char *jid) 77 static char *jidtodisp(const char *jid)
102 { 78 {
303 xmlnode_put_attrib(x, "to", recipient); 279 xmlnode_put_attrib(x, "to", recipient);
304 280
305 switch(st) { 281 switch(st) {
306 case away: 282 case away:
307 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "away", 283 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "away",
308 (unsigned) -1); 284 (unsigned) -1);
309 break; 285 break;
310 286
311 case dontdisturb: 287 case dontdisturb:
312 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "dnd", 288 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "dnd",
313 (unsigned) -1); 289 (unsigned) -1);
314 break; 290 break;
315 291
316 case freeforchat: 292 case freeforchat:
317 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "chat", 293 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "chat",
318 (unsigned) -1); 294 (unsigned) -1);
319 break; 295 break;
320 296
321 case notavail: 297 case notavail:
322 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "xa", 298 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "xa",
323 (unsigned) -1); 299 (unsigned) -1);
324 break; 300 break;
325 301
326 case invisible: 302 case invisible:
327 xmlnode_put_attrib(x, "type", "invisible"); 303 xmlnode_put_attrib(x, "type", "invisible");
328 break; 304 break;
906 break; 882 break;
907 } 883 }
908 previous_state = state; 884 previous_state = state;
909 } 885 }
910 886
911 static void packethandler(jconn conn, jpacket packet) 887 static void handle_packet_iq(jconn conn, char *type, char *from,
888 xmlnode xmldata)
889 {
890 char *p;
891 xmlnode x, y;
892 char *ns = NULL;
893 char *id=NULL;
894
895 if (!type)
896 return;
897
898 if (!strcmp(type, "result")) {
899
900 if ((p = xmlnode_get_attrib(xmldata, "id")) != NULL) {
901 int iid = atoi(p);
902
903 scr_LogPrint(LPRINT_DEBUG, "iid = %d", iid);
904 if (iid == s_id) {
905 if (!regmode) {
906 if (jstate == STATE_GETAUTH) {
907 if ((x = xmlnode_get_tag(xmldata, "query")) != NULL)
908 if (!xmlnode_get_tag(x, "digest")) {
909 jc->sid = 0;
910 }
911
912 s_id = atoi(jab_auth(jc));
913 jstate = STATE_SENDAUTH;
914 } else {
915 gotloggedin();
916 jstate = STATE_LOGGED;
917 }
918 } else {
919 regdone = TRUE;
920 }
921 return;
922 }
923
924 if (!strcmp(p, "VCARDreq")) {
925 x = xmlnode_get_firstchild(xmldata);
926 if (!x) x = xmldata;
927
928 //jhook.gotvcard(ic, x); TODO
929 scr_LogPrint(LPRINT_LOGNORM, "Got VCARD");
930 return;
931 } else if (!strcmp(p, "versionreq")) {
932 // jhook.gotversion(ic, xmldata); TODO
933 scr_LogPrint(LPRINT_LOGNORM, "Got version");
934 return;
935 }
936 }
937
938 if ((x = xmlnode_get_tag(xmldata, "query")) != NULL) {
939 p = xmlnode_get_attrib(x, "xmlns"); if (p) ns = p;
940
941 if (!strcmp(ns, NS_ROSTER)) {
942 gotroster(x);
943 } else if (!strcmp(ns, NS_AGENTS)) {
944 for (y = xmlnode_get_tag(x, "agent"); y; y = xmlnode_get_nextsibling(y)) {
945 const char *alias = xmlnode_get_attrib(y, "jid");
946
947 if (alias) {
948 const char *name = xmlnode_get_tag_data(y, "name");
949 const char *desc = xmlnode_get_tag_data(y, "description");
950 // TODO
951 // const char *service = xmlnode_get_tag_data(y, "service");
952 enum agtype atype = unknown;
953
954 if (xmlnode_get_tag(y, TMSG_GROUPCHAT)) atype = groupchat;
955 else if (xmlnode_get_tag(y, "transport")) atype = transport;
956 else if (xmlnode_get_tag(y, "search")) atype = search;
957
958 if (atype == transport) {
959 char *cleanjid = jidtodisp(alias);
960 roster_add_user(cleanjid, NULL, JABBER_AGENT_GROUP,
961 ROSTER_TYPE_AGENT);
962 g_free(cleanjid);
963 }
964 if (alias && name && desc) {
965 scr_LogPrint(LPRINT_LOGNORM,
966 "Agent: %s / %s / %s / type=%d",
967 alias, name, desc, atype);
968
969 if (atype == search) {
970 x = jutil_iqnew (JPACKET__GET, NS_SEARCH);
971 xmlnode_put_attrib(x, "to", alias);
972 xmlnode_put_attrib(x, "id", "Agent info");
973 jab_send(conn, x);
974 xmlnode_free(x);
975 }
976
977 if (xmlnode_get_tag(y, "register")) {
978 x = jutil_iqnew (JPACKET__GET, NS_REGISTER);
979 xmlnode_put_attrib(x, "to", alias);
980 xmlnode_put_attrib(x, "id", "Agent info");
981 jab_send(conn, x);
982 xmlnode_free(x);
983 }
984 }
985 }
986 }
987
988 /*
989 if (find(jhook.agents.begin(), jhook.agents.end(), DEFAULT_CONFSERV) == jhook.agents.end())
990 jhook.agents.insert(jhook.agents.begin(), agent(DEFAULT_CONFSERV, DEFAULT_CONFSERV,
991 _("Default Jabber conference server"), agent::atGroupchat));
992
993 */
994 } else if (!strcmp(ns, NS_SEARCH) || !strcmp(ns, NS_REGISTER)) {
995 p = xmlnode_get_attrib(xmldata, "id"); id = p ? p : (char*)"";
996
997 if (!strcmp(id, "Agent info")) {
998 // jhook.gotagentinfo(xmldata); TODO
999 scr_LogPrint(LPRINT_LOGNORM, "Got agent info");
1000 } else if (!strcmp(id, "Lookup")) {
1001 // jhook.gotsearchresults(xmldata); TODO
1002 scr_LogPrint(LPRINT_LOGNORM, "Got search results");
1003 } else if (!strcmp(id, "Register")) {
1004 if (!from)
1005 return;
1006 x = jutil_iqnew(JPACKET__GET, NS_REGISTER);
1007 xmlnode_put_attrib(x, "to", from);
1008 xmlnode_put_attrib(x, "id", "Agent info");
1009 jab_send(conn, x);
1010 xmlnode_free(x);
1011 }
1012
1013 }
1014 }
1015 } else if (!strcmp(type, "get")) {
1016 p = xmlnode_get_attrib(xmldata, "id");
1017 if (p) {
1018 xmlnode z;
1019
1020 id = p;
1021 x = xmlnode_new_tag("iq");
1022 xmlnode_put_attrib(x, "type", "result");
1023 xmlnode_put_attrib(x, "to", from);
1024 xmlnode_put_attrib(x, "id", id);
1025 xmlnode_put_attrib(x, "type", TMSG_ERROR);
1026 y = xmlnode_insert_tag(x, TMSG_ERROR);
1027 xmlnode_put_attrib(y, "code", "503");
1028 xmlnode_put_attrib(y, "type", "cancel");
1029 z = xmlnode_insert_tag(y, "feature-not-implemented");
1030 xmlnode_put_attrib(z, "xmlns",
1031 "urn:ietf:params:xml:ns:xmpp-stanzas");
1032 jab_send(conn, x);
1033 xmlnode_free(x);
1034 }
1035 } else if (!strcmp(type, "set")) {
1036 /* FIXME: send error */
1037 } else if (!strcmp(type, TMSG_ERROR)) {
1038 if ((x = xmlnode_get_tag(xmldata, TMSG_ERROR)) != NULL)
1039 display_server_error(x);
1040 }
1041 }
1042
1043 static void handle_packet_presence(jconn conn, char *type, char *from,
1044 xmlnode xmldata)
912 { 1045 {
913 char *p, *r, *s; 1046 char *p, *r, *s;
914 const char *m, *rname; 1047 const char *m;
915 xmlnode x, y; 1048 xmlnode x, y;
916 char *from=NULL, *type=NULL, *body=NULL, *enc=NULL; 1049 const char *rname;
917 char *ns=NULL;
918 char *id=NULL;
919 enum imstatus ust; 1050 enum imstatus ust;
920 char bpprio; 1051 char bpprio;
921 1052
1053 r = jidtodisp(from);
1054 if (type && !strcmp(type, TMSG_ERROR)) {
1055 scr_LogPrint(LPRINT_LOGNORM, "Error presence packet from <%s>", r);
1056 if ((x = xmlnode_get_tag(xmldata, TMSG_ERROR)) != NULL)
1057 display_server_error(x);
1058 g_free(r);
1059 return;
1060 }
1061
1062 p = xmlnode_get_tag_data(xmldata, "priority");
1063 if (p && *p) bpprio = (gchar)atoi(p);
1064 else bpprio = 0;
1065
1066 ust = available;
1067 p = xmlnode_get_tag_data(xmldata, "show");
1068 if (p) {
1069 if (!strcmp(p, "away")) ust = away;
1070 else if (!strcmp(p, "dnd")) ust = dontdisturb;
1071 else if (!strcmp(p, "xa")) ust = notavail;
1072 else if (!strcmp(p, "chat")) ust = freeforchat;
1073 }
1074
1075 if (type && !strcmp(type, "unavailable"))
1076 ust = offline;
1077
1078 s = NULL;
1079 p = xmlnode_get_tag_data(xmldata, "status");
1080 if (p) {
1081 s = from_utf8(p);
1082 if (!s)
1083 scr_LogPrint(LPRINT_LOG,
1084 "Decoding of status message of <%s> has failed: %s",
1085 from, p);
1086 }
1087
1088 // Call hk_statuschange() if status has changed or if the
1089 // status message is different
1090 rname = strchr(from, '/');
1091 if (rname) rname++;
1092
1093 // Check for MUC presence packet
1094 // There can be multiple <x> tags!!
1095 x = xmlnode_get_firstchild(xmldata);
1096 for ( ; x; x = xmlnode_get_nextsibling(x)) {
1097 if ((p = xmlnode_get_name(x)) && !strcmp(p, "x"))
1098 if ((p = xmlnode_get_attrib(x, "xmlns")) &&
1099 !strcasecmp(p, "http://jabber.org/protocol/muc#user"))
1100 break;
1101 }
1102 if (x) { // This is a MUC presence message
1103 enum imrole mbrole = role_none;
1104 const char *mbrjid = NULL;
1105 const char *mbnewnick = NULL;
1106 GSList *room_elt;
1107 int log_muc_conf = settings_opt_get_int("log_muc_conf");
1108
1109 // Add room if it doesn't already exist
1110 room_elt = roster_find(r, jidsearch, 0);
1111 if (!room_elt)
1112 room_elt = roster_add_user(r, NULL, NULL, ROSTER_TYPE_ROOM);
1113 else // Make sure this is a room (it can be a conversion user->room)
1114 buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
1115
1116 // Get room member's information
1117 y = xmlnode_get_tag(x, "item");
1118 if (y) {
1119 p = xmlnode_get_attrib(y, "role");
1120 if (p) {
1121 if (!strcmp(p, "moderator")) mbrole = role_moderator;
1122 else if (!strcmp(p, "participant")) mbrole = role_participant;
1123 else if (!strcmp(p, "visitor")) mbrole = role_visitor;
1124 else if (!strcmp(p, "none")) mbrole = role_none;
1125 else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown role \"%s\"",
1126 from, p);
1127 }
1128 p = xmlnode_get_attrib(y, "jid");
1129 if (p) mbrjid = p;
1130 p = xmlnode_get_attrib(y, "nick");
1131 if (p) mbnewnick = p;
1132 }
1133
1134 // Check for nickname change
1135 y = xmlnode_get_tag(x, "status");
1136 if (y && mbnewnick) {
1137 p = xmlnode_get_attrib(y, "code");
1138 if (p && !strcmp(p, "303")) {
1139 gchar *mbuf;
1140 gchar *newname_noutf8 = from_utf8(mbnewnick);
1141 if (!newname_noutf8)
1142 scr_LogPrint(LPRINT_LOG,
1143 "Decoding of new nickname has failed: %s",
1144 mbnewnick);
1145 mbuf = g_strdup_printf("%s is now known as %s", rname,
1146 (newname_noutf8 ? newname_noutf8 : "(?)"));
1147 scr_WriteIncomingMessage(r, mbuf, 0,
1148 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1149 if (log_muc_conf) hlog_write_message(r, 0, FALSE, mbuf);
1150 g_free(mbuf);
1151 if (newname_noutf8) {
1152 buddy_resource_setname(room_elt->data, rname, newname_noutf8);
1153 m = buddy_getnickname(room_elt->data);
1154 if (m && !strcmp(rname, m))
1155 buddy_setnickname(room_elt->data, newname_noutf8);
1156 g_free(newname_noutf8);
1157 }
1158 }
1159 }
1160
1161 // Check for departure/arrival
1162 if (!mbnewnick && mbrole == role_none) {
1163 gchar *mbuf;
1164
1165 // If this is a leave, check if it is ourself
1166 m = buddy_getnickname(room_elt->data);
1167 if (m && !strcmp(rname, m)) {
1168 // _We_ have left! (kicked, banned, etc.)
1169 buddy_setnickname(room_elt->data, NULL);
1170 buddy_del_all_resources(room_elt->data);
1171 scr_LogPrint(LPRINT_LOGNORM, "You have left %s", r);
1172 scr_WriteIncomingMessage(r, "You have left", 0,
1173 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1174 update_roster = TRUE;
1175
1176 goto out_packet_presence;
1177 }
1178
1179 if (s) mbuf = g_strdup_printf("%s has left: %s", rname, s);
1180 else mbuf = g_strdup_printf("%s has left", rname);
1181 scr_WriteIncomingMessage(r, mbuf, 0,
1182 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1183 if (log_muc_conf) hlog_write_message(r, 0, FALSE, mbuf);
1184 g_free(mbuf);
1185 } else if (buddy_getstatus(room_elt->data, rname) == offline &&
1186 ust != offline) {
1187 gchar *mbuf;
1188 if (buddy_getnickname(room_elt->data) == NULL) {
1189 buddy_setnickname(room_elt->data, rname);
1190 mbuf = g_strdup_printf("You have joined as \"%s\"", rname);
1191 } else {
1192 mbuf = g_strdup_printf("%s has joined", rname);
1193 }
1194 scr_WriteIncomingMessage(r, mbuf, 0,
1195 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1196 if (log_muc_conf) hlog_write_message(r, 0, FALSE, mbuf);
1197 g_free(mbuf);
1198 }
1199
1200 // Update room member status
1201 if (rname)
1202 roster_setstatus(r, rname, bpprio, ust, s, mbrole, mbrjid);
1203 else
1204 scr_LogPrint(LPRINT_LOGNORM, "MUC DBG: no rname!"); /* DBG */
1205
1206 buddylist_build();
1207 scr_DrawRoster();
1208
1209 goto out_packet_presence;
1210 }
1211
1212 // Not a MUC message, so this is a regular buddy...
1213 m = roster_getstatusmsg(r, rname);
1214 if ((ust != roster_getstatus(r, rname)) ||
1215 (!s && m && m[0]) || (s && (!m || strcmp(s, m))))
1216 hk_statuschange(r, rname, bpprio, 0, ust, s);
1217
1218 out_packet_presence:
1219 g_free(r);
1220 if (s) g_free(s);
1221 }
1222
1223 static void handle_packet_message(jconn conn, char *type, char *from,
1224 xmlnode xmldata)
1225 {
1226 char *p, *r, *s;
1227 xmlnode x;
1228 char *body=NULL;
1229 char *enc = NULL;
1230 char *tmp = NULL;
1231 time_t timestamp = 0;
1232
1233 body = xmlnode_get_tag_data(xmldata, "body");
1234
1235 p = xmlnode_get_tag_data(xmldata, "subject");
1236 if (p != NULL) {
1237 if (type && !strcmp(type, TMSG_GROUPCHAT)) { // Room topic
1238 gchar *mbuf;
1239 gchar *subj_noutf8 = from_utf8(p);
1240 if (!subj_noutf8)
1241 scr_LogPrint(LPRINT_LOG,
1242 "Decoding of room topic has failed: %s", p);
1243 // Get the room (s) and the nickname (r)
1244 s = g_strdup(from);
1245 r = strchr(s, '/');
1246 if (r) *r++ = 0;
1247 else r = s;
1248 // Display inside the room window
1249 mbuf = g_strdup_printf("%s has set the topic to: %s", r,
1250 (subj_noutf8 ? subj_noutf8 : "(?)"));
1251 scr_WriteIncomingMessage(s, mbuf, 0,
1252 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1253 if (settings_opt_get_int("log_muc_conf"))
1254 hlog_write_message(s, 0, FALSE, mbuf);
1255 if (subj_noutf8) g_free(subj_noutf8);
1256 g_free(s);
1257 g_free(mbuf);
1258 } else { // Chat message
1259 tmp = g_new(char, (body ? strlen(body) : 0) + strlen(p) + 4);
1260 *tmp = '[';
1261 strcpy(tmp+1, p);
1262 strcat(tmp, "]\n");
1263 if (body) strcat(tmp, body);
1264 body = tmp;
1265 }
1266 }
1267
1268 /* there can be multiple <x> tags. we're looking for one with
1269 xmlns = jabber:x:encrypted */
1270
1271 x = xmlnode_get_firstchild(xmldata);
1272 for ( ; x; x = xmlnode_get_nextsibling(x)) {
1273 if ((p = xmlnode_get_name(x)) && !strcmp(p, "x"))
1274 if ((p = xmlnode_get_attrib(x, "xmlns")) &&
1275 !strcasecmp(p, "jabber:x:encrypted"))
1276 if ((p = xmlnode_get_data(x)) != NULL) {
1277 enc = p;
1278 break;
1279 }
1280 }
1281
1282 // Timestamp?
1283 if ((x = xmlnode_get_tag(xmldata, "x")) != NULL) {
1284 if ((p = xmlnode_get_attrib(x, "stamp")) != NULL)
1285 timestamp = from_iso8601(p, 1);
1286 }
1287
1288 if (type && !strcmp(type, TMSG_ERROR)) {
1289 if ((x = xmlnode_get_tag(xmldata, TMSG_ERROR)) != NULL)
1290 display_server_error(x);
1291 }
1292 if (from && body)
1293 gotmessage(type, from, body, enc, timestamp);
1294 if (tmp)
1295 g_free(tmp);
1296 }
1297
1298 static void handle_packet_s10n(jconn conn, char *type, char *from,
1299 xmlnode xmldata)
1300 {
1301 xmlnode x;
1302
1303 scr_LogPrint(LPRINT_LOGNORM, "Received (un)subscription packet "
1304 "(type=%s)", ((type) ? type : ""));
1305
1306 if (!strcmp(type, "subscribe")) {
1307 char *r;
1308 int isagent;
1309 r = jidtodisp(from);
1310 isagent = (roster_gettype(r) & ROSTER_TYPE_AGENT) != 0;
1311 g_free(r);
1312 //scr_LogPrint(LPRINT_LOGNORM, "isagent=%d", isagent); // XXX DBG
1313 if (!isagent) {
1314 scr_LogPrint(LPRINT_LOGNORM, "<%s> wants to subscribe "
1315 "to your network presence updates", from);
1316 // FIXME we accept everybody...
1317 x = jutil_presnew(JPACKET__SUBSCRIBED, from, 0);
1318 jab_send(jc, x);
1319 xmlnode_free(x);
1320 } else {
1321 x = jutil_presnew(JPACKET__SUBSCRIBED, from, 0);
1322 jab_send(jc, x);
1323 xmlnode_free(x);
1324 }
1325 } else if (!strcmp(type, "unsubscribe")) {
1326 x = jutil_presnew(JPACKET__UNSUBSCRIBED, from, 0);
1327 jab_send(jc, x);
1328 xmlnode_free(x);
1329 scr_LogPrint(LPRINT_LOGNORM, "<%s> has unsubscribed to "
1330 "your presence updates", from);
1331 }
1332 }
1333
1334 static void packethandler(jconn conn, jpacket packet)
1335 {
1336 char *p, *r, *s;
1337 const char *m;
1338 char *from=NULL, *type=NULL;
1339
922 jb_reset_keepalive(); // reset keepalive timeout 1340 jb_reset_keepalive(); // reset keepalive timeout
923 jpacket_reset(packet); 1341 jpacket_reset(packet);
924 1342
925 p = xmlnode_get_attrib(packet->x, "type"); if (p) type = p; 1343 p = xmlnode_get_attrib(packet->x, "type");
1344 if (p) type = p;
1345
926 p = xmlnode_get_attrib(packet->x, "from"); 1346 p = xmlnode_get_attrib(packet->x, "from");
927 if (p) { // Convert from UTF8 1347 if (p) { // Convert from UTF8
928 // We need to be careful because from_utf8() can fail on some chars 1348 // We need to be careful because from_utf8() can fail on some chars
929 // Thus we only convert the resource part 1349 // Thus we only convert the resource part
930 from = g_new0(char, strlen(p)+1); 1350 from = g_new0(char, strlen(p)+1);
951 return; 1371 return;
952 } 1372 }
953 1373
954 switch (packet->type) { 1374 switch (packet->type) {
955 case JPACKET_MESSAGE: 1375 case JPACKET_MESSAGE:
956 { 1376 handle_packet_message(conn, type, from, packet->x);
957 char *tmp = NULL;
958 time_t timestamp = 0;
959
960 body = xmlnode_get_tag_data(packet->x, "body");
961
962 p = xmlnode_get_tag_data(packet->x, "subject");
963 if (p != NULL) {
964 if (type && !strcmp(type, TMSG_GROUPCHAT)) { // Room topic
965 gchar *mbuf;
966 gchar *subj_noutf8 = from_utf8(p);
967 if (!subj_noutf8)
968 scr_LogPrint(LPRINT_LOG,
969 "Decoding of room topic has failed: %s", p);
970 // Get the room (s) and the nickname (r)
971 s = g_strdup(from);
972 r = strchr(s, '/');
973 if (r) *r++ = 0;
974 else r = s;
975 // Display inside the room window
976 mbuf = g_strdup_printf("%s has set the topic to: %s", r,
977 (subj_noutf8 ? subj_noutf8 : "(?)"));
978 scr_WriteIncomingMessage(s, mbuf, 0,
979 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
980 if (settings_opt_get_int("log_muc_conf"))
981 hlog_write_message(s, 0, FALSE, mbuf);
982 if (subj_noutf8) g_free(subj_noutf8);
983 g_free(s);
984 g_free(mbuf);
985 } else { // Chat message
986 tmp = g_new(char, (body ? strlen(body) : 0) + strlen(p) + 4);
987 *tmp = '[';
988 strcpy(tmp+1, p);
989 strcat(tmp, "]\n");
990 if (body) strcat(tmp, body);
991 body = tmp;
992 }
993 }
994
995 /* there can be multiple <x> tags. we're looking for one with
996 xmlns = jabber:x:encrypted */
997
998 x = xmlnode_get_firstchild(packet->x);
999 for ( ; x; x = xmlnode_get_nextsibling(x)) {
1000 if ((p = xmlnode_get_name(x)) && !strcmp(p, "x"))
1001 if ((p = xmlnode_get_attrib(x, "xmlns")) &&
1002 !strcasecmp(p, "jabber:x:encrypted"))
1003 if ((p = xmlnode_get_data(x)) != NULL) {
1004 enc = p;
1005 break;
1006 }
1007 }
1008
1009 // Timestamp?
1010 if ((x = xmlnode_get_tag(packet->x, "x")) != NULL) {
1011 if ((p = xmlnode_get_attrib(x, "stamp")) != NULL)
1012 timestamp = from_iso8601(p, 1);
1013 }
1014
1015 if (type && !strcmp(type, TMSG_ERROR)) {
1016 if ((x = xmlnode_get_tag(packet->x, TMSG_ERROR)) != NULL)
1017 display_server_error(x);
1018 }
1019 if (from && body)
1020 gotmessage(type, from, body, enc, timestamp);
1021 if (tmp)
1022 g_free(tmp);
1023 }
1024 break; 1377 break;
1025 1378
1026 case JPACKET_IQ: 1379 case JPACKET_IQ:
1027 if (!strcmp(type, "result")) { 1380 handle_packet_iq(conn, type, from, packet->x);
1028
1029 if ((p = xmlnode_get_attrib(packet->x, "id")) != NULL) {
1030 int iid = atoi(p);
1031
1032 scr_LogPrint(LPRINT_DEBUG, "iid = %d", iid);
1033 if (iid == s_id) {
1034 if (!regmode) {
1035 if (jstate == STATE_GETAUTH) {
1036 if ((x = xmlnode_get_tag(packet->x, "query")) != NULL)
1037 if (!xmlnode_get_tag(x, "digest")) {
1038 jc->sid = 0;
1039 }
1040
1041 s_id = atoi(jab_auth(jc));
1042 jstate = STATE_SENDAUTH;
1043 } else {
1044 gotloggedin();
1045 jstate = STATE_LOGGED;
1046 }
1047 } else {
1048 regdone = TRUE;
1049 }
1050 return;
1051 }
1052
1053 if (!strcmp(p, "VCARDreq")) {
1054 x = xmlnode_get_firstchild(packet->x);
1055 if (!x) x = packet->x;
1056
1057 //jhook.gotvcard(ic, x); TODO
1058 scr_LogPrint(LPRINT_LOGNORM, "Got VCARD");
1059 return;
1060 } else if (!strcmp(p, "versionreq")) {
1061 // jhook.gotversion(ic, packet->x); TODO
1062 scr_LogPrint(LPRINT_LOGNORM, "Got version");
1063 return;
1064 }
1065 }
1066
1067 if ((x = xmlnode_get_tag(packet->x, "query")) != NULL) {
1068 p = xmlnode_get_attrib(x, "xmlns"); if (p) ns = p;
1069
1070 if (!strcmp(ns, NS_ROSTER)) {
1071 gotroster(x);
1072 } else if (!strcmp(ns, NS_AGENTS)) {
1073 for (y = xmlnode_get_tag(x, "agent"); y; y = xmlnode_get_nextsibling(y)) {
1074 const char *alias = xmlnode_get_attrib(y, "jid");
1075
1076 if (alias) {
1077 const char *name = xmlnode_get_tag_data(y, "name");
1078 const char *desc = xmlnode_get_tag_data(y, "description");
1079 // TODO
1080 // const char *service = xmlnode_get_tag_data(y, "service");
1081 enum agtype atype = unknown;
1082
1083 if (xmlnode_get_tag(y, TMSG_GROUPCHAT)) atype = groupchat;
1084 else if (xmlnode_get_tag(y, "transport")) atype = transport;
1085 else if (xmlnode_get_tag(y, "search")) atype = search;
1086
1087 if (atype == transport) {
1088 char *cleanjid = jidtodisp(alias);
1089 roster_add_user(cleanjid, NULL, JABBER_AGENT_GROUP,
1090 ROSTER_TYPE_AGENT);
1091 g_free(cleanjid);
1092 }
1093 if (alias && name && desc) {
1094 scr_LogPrint(LPRINT_LOGNORM,
1095 "Agent: %s / %s / %s / type=%d",
1096 alias, name, desc, atype);
1097
1098 if (atype == search) {
1099 x = jutil_iqnew (JPACKET__GET, NS_SEARCH);
1100 xmlnode_put_attrib(x, "to", alias);
1101 xmlnode_put_attrib(x, "id", "Agent info");
1102 jab_send(conn, x);
1103 xmlnode_free(x);
1104 }
1105
1106 if (xmlnode_get_tag(y, "register")) {
1107 x = jutil_iqnew (JPACKET__GET, NS_REGISTER);
1108 xmlnode_put_attrib(x, "to", alias);
1109 xmlnode_put_attrib(x, "id", "Agent info");
1110 jab_send(conn, x);
1111 xmlnode_free(x);
1112 }
1113 }
1114 }
1115 }
1116
1117 /*
1118 if (find(jhook.agents.begin(), jhook.agents.end(), DEFAULT_CONFSERV) == jhook.agents.end())
1119 jhook.agents.insert(jhook.agents.begin(), agent(DEFAULT_CONFSERV, DEFAULT_CONFSERV,
1120 _("Default Jabber conference server"), agent::atGroupchat));
1121
1122 */
1123 } else if (!strcmp(ns, NS_SEARCH) || !strcmp(ns, NS_REGISTER)) {
1124 p = xmlnode_get_attrib(packet->x, "id"); id = p ? p : (char*)"";
1125
1126 if (!strcmp(id, "Agent info")) {
1127 // jhook.gotagentinfo(packet->x); TODO
1128 scr_LogPrint(LPRINT_LOGNORM, "Got agent info");
1129 } else if (!strcmp(id, "Lookup")) {
1130 // jhook.gotsearchresults(packet->x); TODO
1131 scr_LogPrint(LPRINT_LOGNORM, "Got search results");
1132 } else if (!strcmp(id, "Register")) {
1133 x = jutil_iqnew(JPACKET__GET, NS_REGISTER);
1134 xmlnode_put_attrib(x, "to", from);
1135 xmlnode_put_attrib(x, "id", "Agent info");
1136 jab_send(conn, x);
1137 xmlnode_free(x);
1138 }
1139
1140 }
1141 }
1142 } else if (!strcmp(type, "get")) {
1143 p = xmlnode_get_attrib(packet->x, "id");
1144 if (p) {
1145 xmlnode z;
1146
1147 id = p;
1148 x = xmlnode_new_tag("iq");
1149 xmlnode_put_attrib(x, "type", "result");
1150 xmlnode_put_attrib(x, "to", from);
1151 xmlnode_put_attrib(x, "id", id);
1152 xmlnode_put_attrib(x, "type", TMSG_ERROR);
1153 y = xmlnode_insert_tag(x, TMSG_ERROR);
1154 xmlnode_put_attrib(y, "code", "503");
1155 xmlnode_put_attrib(y, "type", "cancel");
1156 z = xmlnode_insert_tag(y, "feature-not-implemented");
1157 xmlnode_put_attrib(z, "xmlns",
1158 "urn:ietf:params:xml:ns:xmpp-stanzas");
1159 jab_send(conn, x);
1160 xmlnode_free(x);
1161 }
1162 } else if (!strcmp(type, "set")) {
1163 /* FIXME: send error */
1164 } else if (!strcmp(type, TMSG_ERROR)) {
1165 if ((x = xmlnode_get_tag(packet->x, TMSG_ERROR)) != NULL)
1166 display_server_error(x);
1167 }
1168 break; 1381 break;
1169 1382
1170 case JPACKET_PRESENCE: 1383 case JPACKET_PRESENCE:
1171 r = jidtodisp(from); 1384 handle_packet_presence(conn, type, from, packet->x);
1172 if (type && !strcmp(type, TMSG_ERROR)) {
1173 scr_LogPrint(LPRINT_LOGNORM, "Error presence packet from <%s>", r);
1174 if ((x = xmlnode_get_tag(packet->x, TMSG_ERROR)) != NULL)
1175 display_server_error(x);
1176 g_free(r);
1177 break;
1178 }
1179
1180 p = xmlnode_get_tag_data(packet->x, "priority");
1181 if (p && *p) bpprio = (gchar)atoi(p);
1182 else bpprio = 0;
1183
1184 ust = available;
1185 p = xmlnode_get_tag_data(packet->x, "show");
1186 if (p) {
1187 if (!strcmp(p, "away")) ust = away;
1188 else if (!strcmp(p, "dnd")) ust = dontdisturb;
1189 else if (!strcmp(p, "xa")) ust = notavail;
1190 else if (!strcmp(p, "chat")) ust = freeforchat;
1191 }
1192
1193 if (type && !strcmp(type, "unavailable"))
1194 ust = offline;
1195
1196 s = NULL;
1197 p = xmlnode_get_tag_data(packet->x, "status");
1198 if (p) {
1199 s = from_utf8(p);
1200 if (!s)
1201 scr_LogPrint(LPRINT_LOG,
1202 "Decoding of status message of <%s> has failed: %s",
1203 from, p);
1204 }
1205
1206 // Call hk_statuschange() if status has changed or if the
1207 // status message is different
1208 rname = strchr(from, '/');
1209 if (rname) rname++;
1210
1211 // Check for MUC presence packet
1212 // There can be multiple <x> tags!!
1213 x = xmlnode_get_firstchild(packet->x);
1214 for ( ; x; x = xmlnode_get_nextsibling(x)) {
1215 if ((p = xmlnode_get_name(x)) && !strcmp(p, "x"))
1216 if ((p = xmlnode_get_attrib(x, "xmlns")) &&
1217 !strcasecmp(p, "http://jabber.org/protocol/muc#user"))
1218 break;
1219 }
1220 if (x) { // This is a MUC presence message
1221 enum imrole mbrole = role_none;
1222 const char *mbrjid = NULL;
1223 const char *mbnewnick = NULL;
1224 GSList *room_elt;
1225 int log_muc_conf = settings_opt_get_int("log_muc_conf");
1226
1227 // Add room if it doesn't already exist
1228 room_elt = roster_find(r, jidsearch, 0);
1229 if (!room_elt)
1230 room_elt = roster_add_user(r, NULL, NULL, ROSTER_TYPE_ROOM);
1231 else // Make sure this is a room (it can be a conversion user->room)
1232 buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
1233
1234 // Get room member's information
1235 y = xmlnode_get_tag(x, "item");
1236 if (y) {
1237 p = xmlnode_get_attrib(y, "role");
1238 if (p) {
1239 if (!strcmp(p, "moderator")) mbrole = role_moderator;
1240 else if (!strcmp(p, "participant")) mbrole = role_participant;
1241 else if (!strcmp(p, "visitor")) mbrole = role_visitor;
1242 else if (!strcmp(p, "none")) mbrole = role_none;
1243 else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown role \"%s\"",
1244 from, p);
1245 }
1246 p = xmlnode_get_attrib(y, "jid");
1247 if (p) mbrjid = p;
1248 p = xmlnode_get_attrib(y, "nick");
1249 if (p) mbnewnick = p;
1250 }
1251
1252 // Check for nickname change
1253 y = xmlnode_get_tag(x, "status");
1254 if (y && mbnewnick) {
1255 p = xmlnode_get_attrib(y, "code");
1256 if (p && !strcmp(p, "303")) {
1257 gchar *mbuf;
1258 gchar *newname_noutf8 = from_utf8(mbnewnick);
1259 if (!newname_noutf8)
1260 scr_LogPrint(LPRINT_LOG,
1261 "Decoding of new nickname has failed: %s",
1262 mbnewnick);
1263 mbuf = g_strdup_printf("%s is now known as %s", rname,
1264 (newname_noutf8 ? newname_noutf8 : "(?)"));
1265 scr_WriteIncomingMessage(r, mbuf, 0,
1266 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1267 if (log_muc_conf) hlog_write_message(r, 0, FALSE, mbuf);
1268 g_free(mbuf);
1269 if (newname_noutf8) {
1270 buddy_resource_setname(room_elt->data, rname, newname_noutf8);
1271 m = buddy_getnickname(room_elt->data);
1272 if (m && !strcmp(rname, m))
1273 buddy_setnickname(room_elt->data, newname_noutf8);
1274 g_free(newname_noutf8);
1275 }
1276 }
1277 }
1278
1279 // Check for departure/arrival
1280 if (!mbnewnick && mbrole == role_none) {
1281 gchar *mbuf;
1282
1283 // If this is a leave, check if it is ourself
1284 m = buddy_getnickname(room_elt->data);
1285 if (m && !strcmp(rname, m)) {
1286 // _We_ have left! (kicked, banned, etc.)
1287 buddy_setnickname(room_elt->data, NULL);
1288 buddy_del_all_resources(room_elt->data);
1289 scr_LogPrint(LPRINT_LOGNORM, "You have left %s", r);
1290 scr_WriteIncomingMessage(r, "You have left", 0,
1291 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1292 g_free(r);
1293 if (s) g_free(s);
1294 update_roster = TRUE;
1295 break;
1296 }
1297
1298 if (s) mbuf = g_strdup_printf("%s has left: %s", rname, s);
1299 else mbuf = g_strdup_printf("%s has left", rname);
1300 scr_WriteIncomingMessage(r, mbuf, 0,
1301 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1302 if (log_muc_conf) hlog_write_message(r, 0, FALSE, mbuf);
1303 g_free(mbuf);
1304 } else if (buddy_getstatus(room_elt->data, rname) == offline &&
1305 ust != offline) {
1306 gchar *mbuf;
1307 if (buddy_getnickname(room_elt->data) == NULL) {
1308 buddy_setnickname(room_elt->data, rname);
1309 mbuf = g_strdup_printf("You have joined as \"%s\"", rname);
1310 } else {
1311 mbuf = g_strdup_printf("%s has joined", rname);
1312 }
1313 scr_WriteIncomingMessage(r, mbuf, 0,
1314 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
1315 if (log_muc_conf) hlog_write_message(r, 0, FALSE, mbuf);
1316 g_free(mbuf);
1317 }
1318
1319 // Update room member status
1320 if (rname)
1321 roster_setstatus(r, rname, bpprio, ust, s, mbrole, mbrjid);
1322 else
1323 scr_LogPrint(LPRINT_LOGNORM, "MUC DBG: no rname!"); /* DBG */
1324
1325 g_free(r);
1326 if (s) g_free(s);
1327
1328 buddylist_build();
1329 scr_DrawRoster();
1330 break;
1331 }
1332
1333 // Not a MUC message, so this is a regular buddy...
1334 m = roster_getstatusmsg(r, rname);
1335 if ((ust != roster_getstatus(r, rname)) ||
1336 (!s && m && m[0]) || (s && (!m || strcmp(s, m))))
1337 hk_statuschange(r, rname, bpprio, 0, ust, s);
1338 g_free(r);
1339 if (s) g_free(s);
1340 break; 1385 break;
1341 1386
1342 case JPACKET_S10N: 1387 case JPACKET_S10N:
1343 scr_LogPrint(LPRINT_LOGNORM, "Received (un)subscription packet " 1388 handle_packet_s10n(conn, type, from, packet->x);
1344 "(type=%s)", ((type) ? type : ""));
1345
1346 if (!strcmp(type, "subscribe")) {
1347 int isagent;
1348 r = jidtodisp(from);
1349 isagent = (roster_gettype(r) & ROSTER_TYPE_AGENT) != 0;
1350 g_free(r);
1351 //scr_LogPrint(LPRINT_LOGNORM, "isagent=%d", isagent); // XXX DBG
1352 if (!isagent) {
1353 scr_LogPrint(LPRINT_LOGNORM, "<%s> wants to subscribe "
1354 "to your network presence updates", from);
1355 // FIXME we accept everybody...
1356 x = jutil_presnew(JPACKET__SUBSCRIBED, from, 0);
1357 jab_send(jc, x);
1358 xmlnode_free(x);
1359 } else {
1360 x = jutil_presnew(JPACKET__SUBSCRIBED, from, 0);
1361 jab_send(jc, x);
1362 xmlnode_free(x);
1363 }
1364 } else if (!strcmp(type, "unsubscribe")) {
1365 x = jutil_presnew(JPACKET__UNSUBSCRIBED, from, 0);
1366 jab_send(jc, x);
1367 xmlnode_free(x);
1368 scr_LogPrint(LPRINT_LOGNORM, "<%s> has unsubscribed to "
1369 "your presence updates", from);
1370 }
1371 break; 1389 break;
1372 1390
1373 default: 1391 default:
1374 break; 1392 scr_LogPrint(LPRINT_LOG, "Unhandled packet type (%d)", packet->type);
1375 } 1393 }
1376 g_free(from); 1394 if (from)
1377 } 1395 g_free(from);
1378 1396 }
1397