Mercurial > hg
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 |