Mercurial > ~mikael > mcabber > hg
comparison mcabber/src/jab_iq.c @ 1158:c30c315dc447
XEP-0146 support (Remote Controlling Clients)
author | misc@mandriva.org |
---|---|
date | Thu, 15 Feb 2007 21:49:39 +0100 |
parents | 995dde656033 |
children | 53c0c5be43fa |
comparison
equal
deleted
inserted
replaced
1157:5c857f0f0ab8 | 1158:c30c315dc447 |
---|---|
30 #include "roster.h" | 30 #include "roster.h" |
31 #include "utils.h" | 31 #include "utils.h" |
32 #include "screen.h" | 32 #include "screen.h" |
33 #include "settings.h" | 33 #include "settings.h" |
34 #include "hbuf.h" | 34 #include "hbuf.h" |
35 #include "commands.h" | |
35 | 36 |
36 | 37 |
37 // Bookmarks for IQ:private storage | 38 // Bookmarks for IQ:private storage |
38 xmlnode bookmarks; | 39 xmlnode bookmarks; |
39 // Roster notes for IQ:private storage | 40 // Roster notes for IQ:private storage |
49 vcard_voice = 1<<3, | 50 vcard_voice = 1<<3, |
50 vcard_fax = 1<<4, | 51 vcard_fax = 1<<4, |
51 vcard_cell = 1<<5, | 52 vcard_cell = 1<<5, |
52 vcard_inet = 1<<6, | 53 vcard_inet = 1<<6, |
53 vcard_pref = 1<<7, | 54 vcard_pref = 1<<7, |
55 }; | |
56 | |
57 static void handle_iq_command_set_status(jconn conn, char *from, | |
58 const char *id, xmlnode xmldata); | |
59 | |
60 static void handle_iq_command_leave_groupchats(jconn conn, char *from, | |
61 const char *id, xmlnode xmldata); | |
62 | |
63 typedef void (*adhoc_command_callback)(jconn, char*, const char*, xmlnode); | |
64 | |
65 struct adhoc_command { | |
66 char *name; | |
67 char *description; | |
68 bool only_for_self; | |
69 adhoc_command_callback callback; | |
70 }; | |
71 | |
72 const struct adhoc_command adhoc_command_list[] = { | |
73 { "http://jabber.org/protocol/rc#set-status", | |
74 "Set the client as away", | |
75 1, | |
76 &handle_iq_command_set_status }, | |
77 { "http://jabber.org/protocol/rc#leave-groupchats", | |
78 "Leave groupchats", | |
79 1, | |
80 &handle_iq_command_leave_groupchats }, | |
81 { NULL, NULL, 0, NULL }, | |
82 }; | |
83 | |
84 struct adhoc_status { | |
85 char *name; // the name used by adhoc | |
86 char *description; | |
87 char *status; // the string, used by setstus | |
88 }; | |
89 | |
90 const struct adhoc_status adhoc_status_list[] = { | |
91 {"online", "Online", "avail"}, | |
92 {"chat", "Chat", "free"}, | |
93 {"away", "Away", "away"}, | |
94 {"xd", "Extended away", "notavail"}, | |
95 {"dnd", "Do not disturb", "dnd"}, | |
96 {"invisible", "Invisible", "invisible"}, | |
97 {"offline", "Offline", "offline"}, | |
98 {NULL, NULL, NULL}, | |
54 }; | 99 }; |
55 | 100 |
56 // iqs_new(type, namespace, prefix, timeout) | 101 // iqs_new(type, namespace, prefix, timeout) |
57 // Create a query (GET, SET) IQ structure. This function should not be used | 102 // Create a query (GET, SET) IQ structure. This function should not be used |
58 // for RESULT packets. | 103 // for RESULT packets. |
792 // so we should be there only once. (That's ugly, however) | 837 // so we should be there only once. (That's ugly, however) |
793 jb_setprevstatus(); | 838 jb_setprevstatus(); |
794 } | 839 } |
795 } | 840 } |
796 | 841 |
842 // FIXME highly duplicated code | |
843 // factorisation is doable | |
844 static void send_iq_not_implemented(jconn conn, char *from, xmlnode xmldata) | |
845 { | |
846 xmlnode x, y, z; | |
847 // Not implemented. | |
848 x = xmlnode_dup(xmldata); | |
849 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | |
850 xmlnode_hide_attrib(x, "from"); | |
851 | |
852 xmlnode_put_attrib(x, "type", TMSG_ERROR); | |
853 y = xmlnode_insert_tag(x, TMSG_ERROR); | |
854 xmlnode_put_attrib(y, "code", "501"); | |
855 xmlnode_put_attrib(y, "type", "cancel"); | |
856 z = xmlnode_insert_tag(y, "feature-not-implemented"); | |
857 xmlnode_put_attrib(z, "xmlns", NS_XMPP_STANZAS); | |
858 | |
859 jab_send(conn, x); | |
860 xmlnode_free(x); | |
861 } | |
862 | |
863 /* | |
864 static void send_iq_commands_bad_action(jconn conn, char *from, xmlnode xmldata) | |
865 { | |
866 xmlnode x, y, z; | |
867 | |
868 x = xmlnode_dup(xmldata); | |
869 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | |
870 xmlnode_hide_attrib(x, "from"); | |
871 | |
872 xmlnode_put_attrib(x, "type", TMSG_ERROR); | |
873 y = xmlnode_insert_tag(x, TMSG_ERROR); | |
874 xmlnode_put_attrib(y, "code", "400"); | |
875 xmlnode_put_attrib(y, "type", "modify"); | |
876 z = xmlnode_insert_tag(y, "bad-request"); | |
877 xmlnode_put_attrib(z, "xmlns", NS_XMPP_STANZAS); | |
878 z = xmlnode_insert_tag(y, "bad-action"); | |
879 xmlnode_put_attrib(z, "xmlns", NS_COMMANDS); | |
880 | |
881 jab_send(conn, x); | |
882 xmlnode_free(x); | |
883 } | |
884 */ | |
885 | |
886 static void send_iq_forbidden(jconn conn, char *from, xmlnode xmldata) | |
887 { | |
888 xmlnode x, y, z; | |
889 | |
890 x = xmlnode_dup(xmldata); | |
891 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | |
892 xmlnode_hide_attrib(x, "from"); | |
893 | |
894 xmlnode_put_attrib(x, "type", TMSG_ERROR); | |
895 y = xmlnode_insert_tag(x, TMSG_ERROR); | |
896 xmlnode_put_attrib(y, "code", "403"); | |
897 xmlnode_put_attrib(y, "type", "cancel"); | |
898 z = xmlnode_insert_tag(y, "forbidden"); | |
899 xmlnode_put_attrib(z, "xmlns", NS_XMPP_STANZAS); | |
900 | |
901 jab_send(conn, x); | |
902 xmlnode_free(x); | |
903 } | |
904 | |
905 static void send_iq_commands_malformed_action(jconn conn, char *from, | |
906 xmlnode xmldata) | |
907 { | |
908 xmlnode x, y, z; | |
909 | |
910 x = xmlnode_dup(xmldata); | |
911 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | |
912 xmlnode_hide_attrib(x, "from"); | |
913 | |
914 xmlnode_put_attrib(x, "type", TMSG_ERROR); | |
915 y = xmlnode_insert_tag(x, TMSG_ERROR); | |
916 xmlnode_put_attrib(y, "code", "400"); | |
917 xmlnode_put_attrib(y, "type", "modify"); | |
918 z = xmlnode_insert_tag(y, "bad-request"); | |
919 xmlnode_put_attrib(z, "xmlns", NS_XMPP_STANZAS); | |
920 z = xmlnode_insert_tag(y, "malformed-action"); | |
921 xmlnode_put_attrib(z, "xmlns", NS_COMMANDS); | |
922 | |
923 jab_send(conn, x); | |
924 xmlnode_free(x); | |
925 } | |
926 | |
927 static void handle_iq_commands_list(jconn conn, char *from, const char *id, | |
928 xmlnode xmldata) | |
929 { | |
930 xmlnode x; | |
931 xmlnode myquery; | |
932 jid requester_jid; | |
933 const struct adhoc_command *command; | |
934 bool from_self; | |
935 x = jutil_iqnew(JPACKET__RESULT, NS_DISCO_ITEMS); | |
936 xmlnode_put_attrib(x, "id", id); | |
937 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | |
938 myquery = xmlnode_get_tag(x, "query"); | |
939 | |
940 requester_jid = jid_new(conn->p, xmlnode_get_attrib(xmldata, "from")); | |
941 from_self = !jid_cmpx(conn->user, requester_jid, JID_USER | JID_SERVER); | |
942 | |
943 for (command = adhoc_command_list ; command->name ; command++) { | |
944 if (!command->only_for_self || from_self) { | |
945 xmlnode item; | |
946 item = xmlnode_insert_tag(myquery, "item"); | |
947 xmlnode_put_attrib(item, "node", command->name); | |
948 xmlnode_put_attrib(item, "name", command->description); | |
949 xmlnode_put_attrib(item, "jid", jid_full(conn->user)); | |
950 } | |
951 } | |
952 | |
953 jab_send(jc, x); | |
954 xmlnode_free(x); | |
955 } | |
956 | |
957 static void xmlnode_insert_dataform_result_message(xmlnode node, char *message) | |
958 { | |
959 xmlnode x = xmlnode_insert_tag(node, "x"); | |
960 xmlnode_put_attrib(x, "type", "result"); | |
961 xmlnode_put_attrib(x, "xmlns", "jabber:x:data"); | |
962 | |
963 xmlnode field = xmlnode_insert_tag(x, "field"); | |
964 xmlnode_put_attrib(field, "type", "text-single"); | |
965 xmlnode_put_attrib(field, "var", "message"); | |
966 | |
967 xmlnode value = xmlnode_insert_tag(field, "value"); | |
968 xmlnode_insert_cdata(value, message, -1); | |
969 } | |
970 | |
971 static char *generate_session_id(char *prefix) | |
972 { | |
973 char *result; | |
974 static int counter = 0; | |
975 counter++; | |
976 // TODO better use timezone ? | |
977 result = g_strdup_printf("%s-%i", prefix, counter); | |
978 return result; | |
979 } | |
980 | |
981 static void handle_iq_command_set_status(jconn conn, char *from, const char *id, | |
982 xmlnode xmldata) | |
983 { | |
984 char *action, *node, *sessionid; | |
985 xmlnode iq, command, x, y; | |
986 const struct adhoc_status *s; | |
987 | |
988 x = xmlnode_get_tag(xmldata, "command"); | |
989 action = xmlnode_get_attrib(x, "action"); | |
990 node = xmlnode_get_attrib(x, "node"); | |
991 sessionid = xmlnode_get_attrib(x, "sessionid"); | |
992 | |
993 iq = xmlnode_new_tag("iq"); | |
994 command = xmlnode_insert_tag(iq, "command"); | |
995 xmlnode_put_attrib(command, "node", node); | |
996 xmlnode_put_attrib(command, "xmlns", NS_COMMANDS); | |
997 | |
998 if (!sessionid) { | |
999 sessionid = generate_session_id("set-status"); | |
1000 xmlnode_put_attrib(command, "sessionid", sessionid); | |
1001 g_free(sessionid); | |
1002 xmlnode_put_attrib(command, "status", "executing"); | |
1003 | |
1004 x = xmlnode_insert_tag(command, "x"); | |
1005 xmlnode_put_attrib(x, "type", "form"); | |
1006 xmlnode_put_attrib(x, "xmlns", "jabber:x:data"); | |
1007 | |
1008 y = xmlnode_insert_tag(x, "title"); | |
1009 xmlnode_insert_cdata(y, "Change Status", -1); | |
1010 | |
1011 y = xmlnode_insert_tag(x, "instructions"); | |
1012 xmlnode_insert_cdata(y, "Choose the status and status message", -1); | |
1013 | |
1014 // TODO see if factorisation is possible | |
1015 // (with xmlnode_insert_dataform_result_message) | |
1016 y = xmlnode_insert_tag(x, "field"); | |
1017 xmlnode_put_attrib(y, "type", "hidden"); | |
1018 xmlnode_put_attrib(y, "var", "FORM_TYPE"); | |
1019 | |
1020 xmlnode value = xmlnode_insert_tag(y, "value"); | |
1021 xmlnode_insert_cdata(value, "http://jabber.org/protocol/rc", -1); | |
1022 | |
1023 y = xmlnode_insert_tag(x, "field"); | |
1024 xmlnode_put_attrib(y, "type", "list-single"); | |
1025 xmlnode_put_attrib(y, "var", "status"); | |
1026 xmlnode_put_attrib(y, "label", "Status"); | |
1027 xmlnode_insert_tag(y, "required"); | |
1028 | |
1029 value = xmlnode_insert_tag(y, "value"); | |
1030 // TODO current status | |
1031 xmlnode_insert_cdata(value, "online", -1); | |
1032 for (s = adhoc_status_list; s->name; s++) { | |
1033 xmlnode option = xmlnode_insert_tag(y, "option"); | |
1034 value = xmlnode_insert_tag(option, "value"); | |
1035 xmlnode_insert_cdata(value, s->name, -1); | |
1036 xmlnode_put_attrib(option, "label", s->description); | |
1037 } | |
1038 // TODO add priority ? | |
1039 // I do not think this is useful, user should not have to care of the | |
1040 // priority like gossip and gajim do (misc) | |
1041 y = xmlnode_insert_tag(x, "field"); | |
1042 xmlnode_put_attrib(y, "type", "text-multi"); | |
1043 xmlnode_put_attrib(y, "var", "status-message"); | |
1044 xmlnode_put_attrib(y, "label", "Message"); | |
1045 } | |
1046 else // (if sessionid) | |
1047 { | |
1048 y = xmlnode_get_tag(x, "x?xmlns=jabber:x:data"); | |
1049 if (y) { | |
1050 char *value, *message; | |
1051 value = xmlnode_get_tag_data(xmlnode_get_tag(y, "field?var=status"), | |
1052 "value"); | |
1053 message = xmlnode_get_tag_data(xmlnode_get_tag(y, | |
1054 "field?var=status-message"), "value"); | |
1055 for (s = adhoc_status_list; !s->name || strcmp(s->name, value); s++); | |
1056 if (s->name) { | |
1057 char* status = g_strdup_printf("%s %s", s->status, message); | |
1058 xmlnode_put_attrib(command, "status", "completed"); | |
1059 | |
1060 setstatus(NULL, status); | |
1061 g_free(status); | |
1062 xmlnode_put_attrib(iq, "type", "result"); | |
1063 xmlnode_insert_dataform_result_message(command, "Status was changed"); | |
1064 } | |
1065 } | |
1066 } | |
1067 xmlnode_put_attrib(iq, "to", xmlnode_get_attrib(xmldata, "from")); | |
1068 xmlnode_put_attrib(iq, "id", id); | |
1069 jab_send(jc, iq); | |
1070 xmlnode_free(iq); | |
1071 } | |
1072 | |
1073 static void _callback_foreach_buddy_groupchat(gpointer rosterdata, void *param) | |
1074 { | |
1075 xmlnode value; | |
1076 xmlnode *field; | |
1077 const char *room_jid, *nickname; | |
1078 char *desc; | |
1079 | |
1080 room_jid = buddy_getjid(rosterdata); | |
1081 if (!room_jid) return; | |
1082 nickname = buddy_getnickname(rosterdata); | |
1083 if (!nickname) return; | |
1084 field = param; | |
1085 | |
1086 xmlnode option = xmlnode_insert_tag(*field, "option"); | |
1087 value = xmlnode_insert_tag(option, "value"); | |
1088 xmlnode_insert_cdata(value, room_jid, -1); | |
1089 desc = g_strdup_printf("%s on %s", nickname, room_jid); | |
1090 xmlnode_put_attrib(option, "label", desc); | |
1091 g_free(desc); | |
1092 } | |
1093 | |
1094 static void handle_iq_command_leave_groupchats(jconn conn, char *from, const char *id, | |
1095 xmlnode xmldata) | |
1096 { | |
1097 char *action, *node, *sessionid; | |
1098 xmlnode iq, command, x; | |
1099 | |
1100 x = xmlnode_get_tag(xmldata, "command"); | |
1101 action = xmlnode_get_attrib(x, "action"); | |
1102 node = xmlnode_get_attrib(x, "node"); | |
1103 sessionid = xmlnode_get_attrib(x, "sessionid"); | |
1104 | |
1105 iq = xmlnode_new_tag("iq"); | |
1106 command = xmlnode_insert_tag(iq, "command"); | |
1107 xmlnode_put_attrib(command, "node", node); | |
1108 xmlnode_put_attrib(command, "xmlns", NS_COMMANDS); | |
1109 | |
1110 if (!sessionid) { | |
1111 sessionid = generate_session_id("leave-groupchats"); | |
1112 xmlnode_put_attrib(command, "sessionid", sessionid); | |
1113 g_free(sessionid); | |
1114 xmlnode_put_attrib(command, "status", "executing"); | |
1115 | |
1116 x = xmlnode_insert_tag(command, "x"); | |
1117 xmlnode_put_attrib(x, "type", "form"); | |
1118 xmlnode_put_attrib(x, "xmlns", "jabber:x:data"); | |
1119 | |
1120 xmlnode title = xmlnode_insert_tag(x, "title"); | |
1121 xmlnode_insert_cdata(title, "Leave groupchats", -1); | |
1122 | |
1123 xmlnode instructions = xmlnode_insert_tag(x, "instructions"); | |
1124 xmlnode_insert_cdata(instructions, "What groupchats do you want to leave ?", | |
1125 -1); | |
1126 | |
1127 xmlnode field = xmlnode_insert_tag(x, "field"); | |
1128 xmlnode_put_attrib(field, "type", "hidden"); | |
1129 xmlnode_put_attrib(field, "var", "FORM_TYPE"); | |
1130 | |
1131 xmlnode value = xmlnode_insert_tag(field, "value"); | |
1132 xmlnode_insert_cdata(value, "http://jabber.org/protocol/rc", -1); | |
1133 | |
1134 field = xmlnode_insert_tag(x, "field"); | |
1135 xmlnode_put_attrib(field, "type", "list-multi"); | |
1136 xmlnode_put_attrib(field, "var", "groupchats"); | |
1137 xmlnode_put_attrib(field, "label", "Groupchats : "); | |
1138 xmlnode_insert_tag(field, "required"); | |
1139 | |
1140 foreach_buddy(ROSTER_TYPE_ROOM, &_callback_foreach_buddy_groupchat, &field); | |
1141 } | |
1142 else // (if sessionid) | |
1143 { | |
1144 xmlnode form = xmlnode_get_tag(x, "x?xmlns=jabber:x:data"); | |
1145 if (form) { | |
1146 xmlnode_put_attrib(command, "status", "completed"); | |
1147 xmlnode gc = xmlnode_get_tag(form, "field?var=groupchats"); | |
1148 xmlnode x; | |
1149 | |
1150 for (x = xmlnode_get_firstchild(gc) ; x ; x = xmlnode_get_nextsibling(x)) { | |
1151 char* to_leave = xmlnode_get_tag_data(x, "value"); | |
1152 if (to_leave) { | |
1153 GList* b = buddy_search_jid(to_leave); | |
1154 if (b) | |
1155 room_leave(b->data, "Asked by remote command"); | |
1156 } | |
1157 } | |
1158 xmlnode_put_attrib(iq, "type", "result"); | |
1159 xmlnode_insert_dataform_result_message(command, "Groupchats were leaved"); | |
1160 } | |
1161 } | |
1162 xmlnode_put_attrib(iq, "to", xmlnode_get_attrib(xmldata, "from")); | |
1163 xmlnode_put_attrib(iq, "id", id); | |
1164 jab_send(jc, iq); | |
1165 xmlnode_free(iq); | |
1166 } | |
1167 | |
1168 static void handle_iq_commands(jconn conn, char *from, const char *id, | |
1169 xmlnode xmldata) | |
1170 { | |
1171 jid requester_jid; | |
1172 xmlnode x; | |
1173 const struct adhoc_command *command; | |
1174 | |
1175 requester_jid = jid_new(conn->p, xmlnode_get_attrib(xmldata, "from")); | |
1176 x = xmlnode_get_tag(xmldata, "command"); | |
1177 if (!jid_cmpx(conn->user, requester_jid, JID_USER | JID_SERVER) ) { | |
1178 char *action, *node; | |
1179 action = xmlnode_get_attrib(x, "action"); | |
1180 node = xmlnode_get_attrib(x, "node"); | |
1181 // action can be NULL, in which case it seems to take the default, | |
1182 // ie execute | |
1183 if (!action || !strcmp(action, "execute") || !strcmp(action, "cancel") | |
1184 || !strcmp(action, "next") || !strcmp(action, "complete")) { | |
1185 for (command = adhoc_command_list; command->name; command++) { | |
1186 if (!strcmp(node, command->name)) | |
1187 command->callback(conn, from, id, xmldata); | |
1188 } | |
1189 // "prev" action will get there, as we do not implement it, and do not autorise it | |
1190 } else { | |
1191 send_iq_commands_malformed_action(conn, from, xmldata); | |
1192 } | |
1193 } else { | |
1194 send_iq_forbidden(conn, from, xmldata); | |
1195 } | |
1196 } | |
1197 | |
1198 static void handle_iq_disco_items(jconn conn, char *from, const char *id, | |
1199 xmlnode xmldata) | |
1200 { | |
1201 xmlnode x; | |
1202 char *node; | |
1203 x = xmlnode_get_tag(xmldata, "query"); | |
1204 node = xmlnode_get_attrib(x, "node"); | |
1205 if (node) { | |
1206 if (!strcmp(node, NS_COMMANDS)) { | |
1207 handle_iq_commands_list(conn, from, id, xmldata); | |
1208 } else { | |
1209 send_iq_not_implemented(conn, from, xmldata); | |
1210 } | |
1211 } else { | |
1212 // not sure about this one | |
1213 send_iq_not_implemented(conn, from, xmldata); | |
1214 } | |
1215 } | |
1216 | |
797 static void handle_iq_disco_info(jconn conn, char *from, const char *id, | 1217 static void handle_iq_disco_info(jconn conn, char *from, const char *id, |
798 xmlnode xmldata) | 1218 xmlnode xmldata) |
799 { | 1219 { |
800 xmlnode x, y; | 1220 xmlnode x, y; |
801 xmlnode myquery; | 1221 xmlnode myquery; |
820 "var", NS_TIME); | 1240 "var", NS_TIME); |
821 xmlnode_put_attrib(xmlnode_insert_tag(myquery, "feature"), | 1241 xmlnode_put_attrib(xmlnode_insert_tag(myquery, "feature"), |
822 "var", NS_VERSION); | 1242 "var", NS_VERSION); |
823 xmlnode_put_attrib(xmlnode_insert_tag(myquery, "feature"), | 1243 xmlnode_put_attrib(xmlnode_insert_tag(myquery, "feature"), |
824 "var", NS_PING); | 1244 "var", NS_PING); |
1245 xmlnode_put_attrib(xmlnode_insert_tag(myquery, "feature"), | |
1246 "var", NS_COMMANDS); | |
825 jab_send(jc, x); | 1247 jab_send(jc, x); |
826 xmlnode_free(x); | 1248 xmlnode_free(x); |
827 } | 1249 } |
828 | 1250 |
829 static void handle_iq_ping(jconn conn, char *from, const char *id, | 1251 static void handle_iq_ping(jconn conn, char *from, const char *id, |
917 | 1339 |
918 // This function borrows some code from the Gaim project | 1340 // This function borrows some code from the Gaim project |
919 static void handle_iq_get(jconn conn, char *from, xmlnode xmldata) | 1341 static void handle_iq_get(jconn conn, char *from, xmlnode xmldata) |
920 { | 1342 { |
921 const char *id, *ns; | 1343 const char *id, *ns; |
922 xmlnode x, y, z; | 1344 xmlnode x; |
923 guint iq_not_implemented = FALSE; | 1345 guint iq_not_implemented = FALSE; |
924 | 1346 |
925 id = xmlnode_get_attrib(xmldata, "id"); | 1347 id = xmlnode_get_attrib(xmldata, "id"); |
926 if (!id) { | 1348 if (!id) { |
927 scr_LogPrint(LPRINT_LOG, "IQ get stanza with no ID, ignored."); | 1349 scr_LogPrint(LPRINT_LOG, "IQ get stanza with no ID, ignored."); |
937 | 1359 |
938 x = xmlnode_get_tag(xmldata, "query"); | 1360 x = xmlnode_get_tag(xmldata, "query"); |
939 ns = xmlnode_get_attrib(x, "xmlns"); | 1361 ns = xmlnode_get_attrib(x, "xmlns"); |
940 if (ns && !strcmp(ns, NS_DISCO_INFO)) { | 1362 if (ns && !strcmp(ns, NS_DISCO_INFO)) { |
941 handle_iq_disco_info(conn, from, id, xmldata); | 1363 handle_iq_disco_info(conn, from, id, xmldata); |
1364 } else if (ns && !strcmp(ns, NS_DISCO_ITEMS)) { | |
1365 handle_iq_disco_items(conn, from, id, xmldata); | |
942 } else if (ns && !strcmp(ns, NS_VERSION)) { | 1366 } else if (ns && !strcmp(ns, NS_VERSION)) { |
943 handle_iq_version(conn, from, id, xmldata); | 1367 handle_iq_version(conn, from, id, xmldata); |
944 } else if (ns && !strcmp(ns, NS_TIME)) { | 1368 } else if (ns && !strcmp(ns, NS_TIME)) { |
945 handle_iq_time(conn, from, id, xmldata); | 1369 handle_iq_time(conn, from, id, xmldata); |
946 } else { | 1370 } else { |
948 } | 1372 } |
949 | 1373 |
950 if (!iq_not_implemented) | 1374 if (!iq_not_implemented) |
951 return; | 1375 return; |
952 | 1376 |
953 // Not implemented. | 1377 send_iq_not_implemented(conn, from, xmldata); |
954 x = xmlnode_dup(xmldata); | |
955 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | |
956 xmlnode_hide_attrib(x, "from"); | |
957 | |
958 xmlnode_put_attrib(x, "type", TMSG_ERROR); | |
959 y = xmlnode_insert_tag(x, TMSG_ERROR); | |
960 xmlnode_put_attrib(y, "code", "501"); | |
961 xmlnode_put_attrib(y, "type", "cancel"); | |
962 z = xmlnode_insert_tag(y, "feature-not-implemented"); | |
963 xmlnode_put_attrib(z, "xmlns", NS_XMPP_STANZAS); | |
964 | |
965 jab_send(conn, x); | |
966 xmlnode_free(x); | |
967 } | 1378 } |
968 | 1379 |
969 static void handle_iq_set(jconn conn, char *from, xmlnode xmldata) | 1380 static void handle_iq_set(jconn conn, char *from, xmlnode xmldata) |
970 { | 1381 { |
971 const char *id, *ns; | 1382 const char *id, *ns; |
972 xmlnode x, y, z; | 1383 xmlnode x; |
973 guint iq_not_implemented = FALSE; | 1384 guint iq_not_implemented = FALSE; |
974 | 1385 |
975 id = xmlnode_get_attrib(xmldata, "id"); | 1386 id = xmlnode_get_attrib(xmldata, "id"); |
976 if (!id) | 1387 if (!id) |
977 scr_LogPrint(LPRINT_LOG, "IQ set stanza with no ID..."); | 1388 scr_LogPrint(LPRINT_LOG, "IQ set stanza with no ID..."); |
979 x = xmlnode_get_tag(xmldata, "query"); | 1390 x = xmlnode_get_tag(xmldata, "query"); |
980 ns = xmlnode_get_attrib(x, "xmlns"); | 1391 ns = xmlnode_get_attrib(x, "xmlns"); |
981 if (ns && !strcmp(ns, NS_ROSTER)) { | 1392 if (ns && !strcmp(ns, NS_ROSTER)) { |
982 handle_iq_roster(x); | 1393 handle_iq_roster(x); |
983 } else { | 1394 } else { |
984 iq_not_implemented = TRUE; | 1395 x = xmlnode_get_tag(xmldata, "command"); |
1396 ns = xmlnode_get_attrib(x, "xmlns"); | |
1397 if (ns && !strcmp(ns, NS_COMMANDS)) { | |
1398 handle_iq_commands(conn, from, id, xmldata); | |
1399 } else { | |
1400 iq_not_implemented = TRUE; | |
1401 } | |
985 } | 1402 } |
986 | 1403 |
987 if (!id) return; | 1404 if (!id) return; |
988 | 1405 |
989 if (!iq_not_implemented) { | 1406 if (!iq_not_implemented) { |
990 x = xmlnode_new_tag("iq"); | 1407 x = xmlnode_new_tag("iq"); |
991 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | 1408 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); |
992 xmlnode_put_attrib(x, "type", "result"); | 1409 xmlnode_put_attrib(x, "type", "result"); |
993 xmlnode_put_attrib(x, "id", id); | 1410 xmlnode_put_attrib(x, "id", id); |
1411 jab_send(conn, x); | |
1412 xmlnode_free(x); | |
994 } else { | 1413 } else { |
995 /* Not implemented yet: send an error stanza */ | 1414 send_iq_not_implemented(conn, from, xmldata); |
996 x = xmlnode_dup(xmldata); | 1415 } |
997 xmlnode_put_attrib(x, "to", xmlnode_get_attrib(xmldata, "from")); | |
998 xmlnode_hide_attrib(x, "from"); | |
999 xmlnode_put_attrib(x, "type", "result"); | |
1000 xmlnode_put_attrib(x, "type", TMSG_ERROR); | |
1001 y = xmlnode_insert_tag(x, TMSG_ERROR); | |
1002 xmlnode_put_attrib(y, "code", "501"); | |
1003 xmlnode_put_attrib(y, "type", "cancel"); | |
1004 z = xmlnode_insert_tag(y, "feature-not-implemented"); | |
1005 xmlnode_put_attrib(z, "xmlns", NS_XMPP_STANZAS); | |
1006 } | |
1007 | |
1008 jab_send(conn, x); | |
1009 xmlnode_free(x); | |
1010 } | 1416 } |
1011 | 1417 |
1012 void handle_packet_iq(jconn conn, char *type, char *from, xmlnode xmldata) | 1418 void handle_packet_iq(jconn conn, char *type, char *from, xmlnode xmldata) |
1013 { | 1419 { |
1014 if (!type) | 1420 if (!type) |