mcabber/src/jab_iq.c
changeset 1158 c30c315dc447
parent 1134 995dde656033
child 1159 53c0c5be43fa
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)