mcabber/src/jabglue.c
changeset 1058 c0d44a9a99bc
parent 1055 6eb1efea75d0
child 1065 230dca34dbea
equal deleted inserted replaced
1057:4cdf19d9c74e 1058:c0d44a9a99bc
    64 }
    64 }
    65 
    65 
    66 //  jidtodisp(jid)
    66 //  jidtodisp(jid)
    67 // Strips the resource part from the jid
    67 // Strips the resource part from the jid
    68 // The caller should g_free the result after use.
    68 // The caller should g_free the result after use.
    69 char *jidtodisp(const char *jid)
    69 char *jidtodisp(const char *fjid)
    70 {
    70 {
    71   char *ptr;
    71   char *ptr;
    72   char *alias;
    72   char *alias;
    73 
    73 
    74   alias = g_strdup(jid);
    74   alias = g_strdup(fjid);
    75 
    75 
    76   if ((ptr = strchr(alias, JID_RESOURCE_SEPARATOR)) != NULL) {
    76   if ((ptr = strchr(alias, JID_RESOURCE_SEPARATOR)) != NULL) {
    77     *ptr = 0;
    77     *ptr = 0;
    78   }
    78   }
    79   return alias;
    79   return alias;
    80 }
    80 }
    81 
    81 
    82 char *compose_jid(const char *username, const char *servername,
    82 char *compose_jid(const char *username, const char *servername,
    83                   const char *resource)
    83                   const char *resource)
    84 {
    84 {
    85   char *jid = g_new(char, 3 +
    85   char *fjid = g_new(char, 3 +
    86                     strlen(username) + strlen(servername) + strlen(resource));
    86                      strlen(username) + strlen(servername) + strlen(resource));
    87   strcpy(jid, username);
    87   strcpy(fjid, username);
    88   if (!strchr(jid, JID_DOMAIN_SEPARATOR)) {
    88   if (!strchr(fjid, JID_DOMAIN_SEPARATOR)) {
    89     strcat(jid, JID_DOMAIN_SEPARATORSTR);
    89     strcat(fjid, JID_DOMAIN_SEPARATORSTR);
    90     strcat(jid, servername);
    90     strcat(fjid, servername);
    91   }
    91   }
    92   strcat(jid, JID_RESOURCE_SEPARATORSTR);
    92   strcat(fjid, JID_RESOURCE_SEPARATORSTR);
    93   strcat(jid, resource);
    93   strcat(fjid, resource);
    94   return jid;
    94   return fjid;
    95 }
    95 }
    96 
    96 
    97 inline unsigned char jb_getonline(void)
    97 inline unsigned char jb_getonline(void)
    98 {
    98 {
    99   return online;
    99   return online;
   100 }
   100 }
   101 
   101 
   102 jconn jb_connect(const char *jid, const char *server, unsigned int port,
   102 jconn jb_connect(const char *fjid, const char *server, unsigned int port,
   103                  int ssl, const char *pass)
   103                  int ssl, const char *pass)
   104 {
   104 {
   105   if (!port) {
   105   if (!port) {
   106     if (ssl)
   106     if (ssl)
   107       port = JABBERSSLPORT;
   107       port = JABBERSSLPORT;
   109       port = JABBERPORT;
   109       port = JABBERPORT;
   110   }
   110   }
   111 
   111 
   112   jb_disconnect();
   112   jb_disconnect();
   113 
   113 
   114   if (!jid) return jc;
   114   if (!fjid) return jc;
   115 
   115 
   116   jc = jab_new((char*)jid, (char*)pass, (char*)server, port, ssl);
   116   jc = jab_new((char*)fjid, (char*)pass, (char*)server, port, ssl);
   117 
   117 
   118   /* These 3 functions can deal with a NULL jc, no worry... */
   118   /* These 3 functions can deal with a NULL jc, no worry... */
   119   jab_logger(jc, logger);
   119   jab_logger(jc, logger);
   120   jab_packet_handler(jc, &packethandler);
   120   jab_packet_handler(jc, &packethandler);
   121   jab_state_handler(jc, &statehandler);
   121   jab_state_handler(jc, &statehandler);
   209 
   209 
   210 void jb_main()
   210 void jb_main()
   211 {
   211 {
   212   time_t now;
   212   time_t now;
   213   fd_set fds;
   213   fd_set fds;
   214   long timeout;
   214   long tmout;
   215   struct timeval tv;
   215   struct timeval tv;
   216   static time_t last_eviqs_check = 0L;
   216   static time_t last_eviqs_check = 0L;
   217 
   217 
   218   if (!online) {
   218   if (!online) {
   219     safe_usleep(10000);
   219     safe_usleep(10000);
   243       tv.tv_sec = LastPingTime + (time_t)KeepaliveDelay - now;
   243       tv.tv_sec = LastPingTime + (time_t)KeepaliveDelay - now;
   244     }
   244     }
   245   }
   245   }
   246 
   246 
   247   // Check auto-away timeout
   247   // Check auto-away timeout
   248   timeout = scr_GetAutoAwayTimeout(now);
   248   tmout = scr_GetAutoAwayTimeout(now);
   249   if (tv.tv_sec > timeout) {
   249   if (tv.tv_sec > tmout) {
   250     tv.tv_sec = timeout;
   250     tv.tv_sec = tmout;
   251   }
   251   }
   252 
   252 
   253 #if defined JEP0022 || defined JEP0085
   253 #if defined JEP0022 || defined JEP0085
   254   // Check composing timeout
   254   // Check composing timeout
   255   timeout = scr_GetChatStatesTimeout(now);
   255   tmout = scr_GetChatStatesTimeout(now);
   256   if (tv.tv_sec > timeout) {
   256   if (tv.tv_sec > tmout) {
   257     tv.tv_sec = timeout;
   257     tv.tv_sec = tmout;
   258   }
   258   }
   259 #endif
   259 #endif
   260 
   260 
   261   if (!tv.tv_sec)
   261   if (!tv.tv_sec)
   262     tv.tv_usec = 350000;
   262     tv.tv_usec = 350000;
   321   return mystatusmsg;
   321   return mystatusmsg;
   322 }
   322 }
   323 
   323 
   324 static void roompresence(gpointer room, void *presencedata)
   324 static void roompresence(gpointer room, void *presencedata)
   325 {
   325 {
   326   const char *jid;
   326   const char *bjid;
   327   const char *nickname;
   327   const char *nickname;
   328   char *to;
   328   char *to;
   329   struct T_presence *pres = presencedata;
   329   struct T_presence *pres = presencedata;
   330 
   330 
   331   if (!buddy_getinsideroom(room))
   331   if (!buddy_getinsideroom(room))
   332     return;
   332     return;
   333 
   333 
   334   jid = buddy_getjid(room);
   334   bjid = buddy_getjid(room);
   335   if (!jid) return;
   335   if (!bjid) return;
   336   nickname = buddy_getnickname(room);
   336   nickname = buddy_getnickname(room);
   337   if (!nickname) return;
   337   if (!nickname) return;
   338 
   338 
   339   to = g_strdup_printf("%s/%s", jid, nickname);
   339   to = g_strdup_printf("%s/%s", bjid, nickname);
   340   jb_setstatus(pres->st, to, pres->msg, TRUE);
   340   jb_setstatus(pres->st, to, pres->msg, TRUE);
   341   g_free(to);
   341   g_free(to);
   342 }
   342 }
   343 
   343 
   344 //  presnew(status, recipient, message)
   344 //  presnew(status, recipient, message)
   507 }
   507 }
   508 
   508 
   509 //  jb_send_msg(jid, test, type, subject, msgid, *encrypted)
   509 //  jb_send_msg(jid, test, type, subject, msgid, *encrypted)
   510 // When encrypted is not NULL, the function set *encrypted to TRUE if the
   510 // When encrypted is not NULL, the function set *encrypted to TRUE if the
   511 // message has been PGP-encrypted.
   511 // message has been PGP-encrypted.
   512 void jb_send_msg(const char *jid, const char *text, int type,
   512 void jb_send_msg(const char *fjid, const char *text, int type,
   513                  const char *subject, const char *msgid, guint *encrypted)
   513                  const char *subject, const char *msgid, guint *encrypted)
   514 {
   514 {
   515   xmlnode x;
   515   xmlnode x;
   516   gchar *strtype;
   516   gchar *strtype;
   517 #if defined HAVE_GPGME || defined JEP0022 || defined JEP0085
   517 #if defined HAVE_GPGME || defined JEP0022 || defined JEP0085
   534     strtype = TMSG_GROUPCHAT;
   534     strtype = TMSG_GROUPCHAT;
   535   else
   535   else
   536     strtype = TMSG_CHAT;
   536     strtype = TMSG_CHAT;
   537 
   537 
   538 #if defined HAVE_GPGME || defined JEP0022 || defined JEP0085
   538 #if defined HAVE_GPGME || defined JEP0022 || defined JEP0085
   539   rname = strchr(jid, JID_RESOURCE_SEPARATOR);
   539   rname = strchr(fjid, JID_RESOURCE_SEPARATOR);
   540   barejid = jidtodisp(jid);
   540   barejid = jidtodisp(fjid);
   541   sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER);
   541   sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER);
   542   g_free(barejid);
   542   g_free(barejid);
   543 
   543 
   544   // If we can get a resource name, we use it.  Else we use NULL,
   544   // If we can get a resource name, we use it.  Else we use NULL,
   545   // which hopefully will give us the most likely resource.
   545   // which hopefully will give us the most likely resource.
   554     if (res_pgpdata && res_pgpdata->sign_keyid)
   554     if (res_pgpdata && res_pgpdata->sign_keyid)
   555       enc = gpg_encrypt(text, res_pgpdata->sign_keyid);
   555       enc = gpg_encrypt(text, res_pgpdata->sign_keyid);
   556   }
   556   }
   557 #endif
   557 #endif
   558 
   558 
   559   x = jutil_msgnew(strtype, (char*)jid, NULL,
   559   x = jutil_msgnew(strtype, (char*)fjid, NULL,
   560                    (enc ? "This message is PGP-encrypted." : (char*)text));
   560                    (enc ? "This message is PGP-encrypted." : (char*)text));
   561   if (subject) {
   561   if (subject) {
   562     xmlnode y;
   562     xmlnode y;
   563     y = xmlnode_insert_tag(x, "subject");
   563     y = xmlnode_insert_tag(x, "subject");
   564     xmlnode_insert_cdata(y, subject, (unsigned) -1);
   564     xmlnode_insert_cdata(y, subject, (unsigned) -1);
   642 
   642 
   643 
   643 
   644 #ifdef JEP0085
   644 #ifdef JEP0085
   645 //  jb_send_jep85_chatstate()
   645 //  jb_send_jep85_chatstate()
   646 // Send a JEP-85 chatstate.
   646 // Send a JEP-85 chatstate.
   647 static void jb_send_jep85_chatstate(const char *jid, guint state)
   647 static void jb_send_jep85_chatstate(const char *fjid, guint state)
   648 {
   648 {
   649   xmlnode x;
   649   xmlnode x;
   650   xmlnode event;
   650   xmlnode event;
   651   char *rname, *barejid;
   651   char *rname, *barejid;
   652   GSList *sl_buddy;
   652   GSList *sl_buddy;
   653   const char *chattag;
   653   const char *chattag;
   654   struct jep0085 *jep85 = NULL;
   654   struct jep0085 *jep85 = NULL;
   655 
   655 
   656   if (!online) return;
   656   if (!online) return;
   657 
   657 
   658   rname = strchr(jid, JID_RESOURCE_SEPARATOR);
   658   rname = strchr(fjid, JID_RESOURCE_SEPARATOR);
   659   barejid = jidtodisp(jid);
   659   barejid = jidtodisp(fjid);
   660   sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER);
   660   sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER);
   661   g_free(barejid);
   661   g_free(barejid);
   662 
   662 
   663   // If we can get a resource name, we use it.  Else we use NULL,
   663   // If we can get a resource name, we use it.  Else we use NULL,
   664   // which hopefully will give us the most likely resource.
   664   // which hopefully will give us the most likely resource.
   684     return;
   684     return;
   685   }
   685   }
   686 
   686 
   687   jep85->last_state_sent = state;
   687   jep85->last_state_sent = state;
   688 
   688 
   689   x = jutil_msgnew(TMSG_CHAT, (char*)jid, NULL, NULL);
   689   x = jutil_msgnew(TMSG_CHAT, (char*)fjid, NULL, NULL);
   690 
   690 
   691   event = xmlnode_insert_tag(x, chattag);
   691   event = xmlnode_insert_tag(x, chattag);
   692   xmlnode_put_attrib(event, "xmlns", NS_CHATSTATES);
   692   xmlnode_put_attrib(event, "xmlns", NS_CHATSTATES);
   693 
   693 
   694   jab_send(jc, x);
   694   jab_send(jc, x);
   699 #endif
   699 #endif
   700 
   700 
   701 #ifdef JEP0022
   701 #ifdef JEP0022
   702 //  jb_send_jep22_event()
   702 //  jb_send_jep22_event()
   703 // Send a JEP-22 message event (delivered, composing...).
   703 // Send a JEP-22 message event (delivered, composing...).
   704 static void jb_send_jep22_event(const char *jid, guint type)
   704 static void jb_send_jep22_event(const char *fjid, guint type)
   705 {
   705 {
   706   xmlnode x;
   706   xmlnode x;
   707   xmlnode event;
   707   xmlnode event;
   708   const char *msgid;
   708   const char *msgid;
   709   char *rname, *barejid;
   709   char *rname, *barejid;
   711   struct jep0022 *jep22 = NULL;
   711   struct jep0022 *jep22 = NULL;
   712   guint jep22_state;
   712   guint jep22_state;
   713 
   713 
   714   if (!online) return;
   714   if (!online) return;
   715 
   715 
   716   rname = strchr(jid, JID_RESOURCE_SEPARATOR);
   716   rname = strchr(fjid, JID_RESOURCE_SEPARATOR);
   717   barejid = jidtodisp(jid);
   717   barejid = jidtodisp(fjid);
   718   sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER);
   718   sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER);
   719   g_free(barejid);
   719   g_free(barejid);
   720 
   720 
   721   // If we can get a resource name, we use it.  Else we use NULL,
   721   // If we can get a resource name, we use it.  Else we use NULL,
   722   // which hopefully will give us the most likely resource.
   722   // which hopefully will give us the most likely resource.
   745     if (jep22_state == jep22->last_state_sent)
   745     if (jep22_state == jep22->last_state_sent)
   746       return;
   746       return;
   747     jep22->last_state_sent = jep22_state;
   747     jep22->last_state_sent = jep22_state;
   748   }
   748   }
   749 
   749 
   750   x = jutil_msgnew(TMSG_CHAT, (char*)jid, NULL, NULL);
   750   x = jutil_msgnew(TMSG_CHAT, (char*)fjid, NULL, NULL);
   751 
   751 
   752   event = xmlnode_insert_tag(x, "x");
   752   event = xmlnode_insert_tag(x, "x");
   753   xmlnode_put_attrib(event, "xmlns", NS_EVENT);
   753   xmlnode_put_attrib(event, "xmlns", NS_EVENT);
   754   if (type == ROSTER_EVENT_DELIVERED)
   754   if (type == ROSTER_EVENT_DELIVERED)
   755     xmlnode_insert_tag(event, "delivered");
   755     xmlnode_insert_tag(event, "delivered");
   768 // Send a chatstate or event (JEP-22/85) according to the buddy's capabilities.
   768 // Send a chatstate or event (JEP-22/85) according to the buddy's capabilities.
   769 // The message is sent to one of the resources with the highest priority.
   769 // The message is sent to one of the resources with the highest priority.
   770 #if defined JEP0022 || defined JEP0085
   770 #if defined JEP0022 || defined JEP0085
   771 void jb_send_chatstate(gpointer buddy, guint chatstate)
   771 void jb_send_chatstate(gpointer buddy, guint chatstate)
   772 {
   772 {
   773   const char *jid;
   773   const char *bjid;
   774   struct jep0085 *jep85 = NULL;
   774   struct jep0085 *jep85 = NULL;
   775   struct jep0022 *jep22 = NULL;
   775   struct jep0022 *jep22 = NULL;
   776 
   776 
   777   jid = buddy_getjid(buddy);
   777   bjid = buddy_getjid(buddy);
   778   if (!jid) return;
   778   if (!bjid) return;
   779 
   779 
   780 #ifdef JEP0085
   780 #ifdef JEP0085
   781   jep85 = buddy_resource_jep85(buddy, NULL);
   781   jep85 = buddy_resource_jep85(buddy, NULL);
   782   if (jep85 && jep85->support == CHATSTATES_SUPPORT_OK) {
   782   if (jep85 && jep85->support == CHATSTATES_SUPPORT_OK) {
   783     jb_send_jep85_chatstate(jid, chatstate);
   783     jb_send_jep85_chatstate(bjid, chatstate);
   784     return;
   784     return;
   785   }
   785   }
   786 #endif
   786 #endif
   787 #ifdef JEP0022
   787 #ifdef JEP0022
   788   jep22 = buddy_resource_jep22(buddy, NULL);
   788   jep22 = buddy_resource_jep22(buddy, NULL);
   789   if (jep22 && jep22->support == CHATSTATES_SUPPORT_OK) {
   789   if (jep22 && jep22->support == CHATSTATES_SUPPORT_OK) {
   790     jb_send_jep22_event(jid, chatstate);
   790     jb_send_jep22_event(bjid, chatstate);
   791   }
   791   }
   792 #endif
   792 #endif
   793 }
   793 }
   794 #endif
   794 #endif
   795 
   795 
   825 }
   825 }
   826 #endif
   826 #endif
   827 
   827 
   828 //  jb_subscr_send_auth(jid)
   828 //  jb_subscr_send_auth(jid)
   829 // Allow jid to receive our presence updates
   829 // Allow jid to receive our presence updates
   830 void jb_subscr_send_auth(const char *jid)
   830 void jb_subscr_send_auth(const char *bjid)
   831 {
   831 {
   832   xmlnode x;
   832   xmlnode x;
   833 
   833 
   834   x = jutil_presnew(JPACKET__SUBSCRIBED, (char *)jid, NULL);
   834   x = jutil_presnew(JPACKET__SUBSCRIBED, (char *)bjid, NULL);
   835   jab_send(jc, x);
   835   jab_send(jc, x);
   836   xmlnode_free(x);
   836   xmlnode_free(x);
   837 }
   837 }
   838 
   838 
   839 //  jb_subscr_cancel_auth(jid)
   839 //  jb_subscr_cancel_auth(jid)
   840 // Cancel jid's subscription to our presence updates
   840 // Cancel jid's subscription to our presence updates
   841 void jb_subscr_cancel_auth(const char *jid)
   841 void jb_subscr_cancel_auth(const char *bjid)
   842 {
   842 {
   843   xmlnode x;
   843   xmlnode x;
   844 
   844 
   845   x = jutil_presnew(JPACKET__UNSUBSCRIBED, (char *)jid, NULL);
   845   x = jutil_presnew(JPACKET__UNSUBSCRIBED, (char *)bjid, NULL);
   846   jab_send(jc, x);
   846   jab_send(jc, x);
   847   xmlnode_free(x);
   847   xmlnode_free(x);
   848 }
   848 }
   849 
   849 
   850 //  jb_subscr_request_auth(jid)
   850 //  jb_subscr_request_auth(jid)
   851 // Request a subscription to jid's presence updates
   851 // Request a subscription to jid's presence updates
   852 void jb_subscr_request_auth(const char *jid)
   852 void jb_subscr_request_auth(const char *bjid)
   853 {
   853 {
   854   xmlnode x;
   854   xmlnode x;
   855 
   855 
   856   x = jutil_presnew(JPACKET__SUBSCRIBE, (char *)jid, NULL);
   856   x = jutil_presnew(JPACKET__SUBSCRIBE, (char *)bjid, NULL);
   857   jab_send(jc, x);
   857   jab_send(jc, x);
   858   xmlnode_free(x);
   858   xmlnode_free(x);
   859 }
   859 }
   860 
   860 
   861 //  jb_subscr_request_cancel(jid)
   861 //  jb_subscr_request_cancel(jid)
   862 // Request to cancel jour subscription to jid's presence updates
   862 // Request to cancel jour subscription to jid's presence updates
   863 void jb_subscr_request_cancel(const char *jid)
   863 void jb_subscr_request_cancel(const char *bjid)
   864 {
   864 {
   865   xmlnode x;
   865   xmlnode x;
   866 
   866 
   867   x = jutil_presnew(JPACKET__UNSUBSCRIBE, (char *)jid, NULL);
   867   x = jutil_presnew(JPACKET__UNSUBSCRIBE, (char *)bjid, NULL);
   868   jab_send(jc, x);
   868   jab_send(jc, x);
   869   xmlnode_free(x);
   869   xmlnode_free(x);
   870 }
   870 }
   871 
   871 
   872 // Note: the caller should check the jid is correct
   872 // Note: the caller should check the jid is correct
   873 void jb_addbuddy(const char *jid, const char *name, const char *group)
   873 void jb_addbuddy(const char *bjid, const char *name, const char *group)
   874 {
   874 {
   875   xmlnode y, z;
   875   xmlnode y, z;
   876   eviqs *iqn;
   876   eviqs *iqn;
   877   char *cleanjid;
   877   char *cleanjid;
   878 
   878 
   879   if (!online) return;
   879   if (!online) return;
   880 
   880 
   881   cleanjid = jidtodisp(jid);
   881   cleanjid = jidtodisp(bjid); // Stripping resource, just in case...
   882 
   882 
   883   // We don't check if the jabber user already exists in the roster,
   883   // We don't check if the jabber user already exists in the roster,
   884   // because it allows to re-ask for notification.
   884   // because it allows to re-ask for notification.
   885 
   885 
   886   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   886   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   906   buddylist_build();
   906   buddylist_build();
   907 
   907 
   908   update_roster = TRUE;
   908   update_roster = TRUE;
   909 }
   909 }
   910 
   910 
   911 void jb_delbuddy(const char *jid)
   911 void jb_delbuddy(const char *bjid)
   912 {
   912 {
   913   xmlnode y, z;
   913   xmlnode y, z;
   914   eviqs *iqn;
   914   eviqs *iqn;
   915   char *cleanjid;
   915   char *cleanjid;
   916 
   916 
   917   if (!online) return;
   917   if (!online) return;
   918 
   918 
   919   cleanjid = jidtodisp(jid);
   919   cleanjid = jidtodisp(bjid); // Stripping resource, just in case...
   920 
   920 
   921   // If the current buddy is an agent, unsubscribe from it
   921   // If the current buddy is an agent, unsubscribe from it
   922   if (roster_gettype(cleanjid) == ROSTER_TYPE_AGENT) {
   922   if (roster_gettype(cleanjid) == ROSTER_TYPE_AGENT) {
   923     scr_LogPrint(LPRINT_LOGNORM, "Unregistering from the %s agent", cleanjid);
   923     scr_LogPrint(LPRINT_LOGNORM, "Unregistering from the %s agent", cleanjid);
   924 
   924 
   948   buddylist_build();
   948   buddylist_build();
   949 
   949 
   950   update_roster = TRUE;
   950   update_roster = TRUE;
   951 }
   951 }
   952 
   952 
   953 void jb_updatebuddy(const char *jid, const char *name, const char *group)
   953 void jb_updatebuddy(const char *bjid, const char *name, const char *group)
   954 {
   954 {
   955   xmlnode y;
   955   xmlnode y;
   956   eviqs *iqn;
   956   eviqs *iqn;
   957   char *cleanjid;
   957   char *cleanjid;
   958 
   958 
   959   if (!online) return;
   959   if (!online) return;
   960 
   960 
   961   // XXX We should check name's and group's correctness
   961   // XXX We should check name's and group's correctness
   962 
   962 
   963   cleanjid = jidtodisp(jid);
   963   cleanjid = jidtodisp(bjid); // Stripping resource, just in case...
   964 
   964 
   965   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   965   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   966   y = xmlnode_insert_tag(xmlnode_get_tag(iqn->xmldata, "query"), "item");
   966   y = xmlnode_insert_tag(xmlnode_get_tag(iqn->xmldata, "query"), "item");
   967   xmlnode_put_attrib(y, "jid", cleanjid);
   967   xmlnode_put_attrib(y, "jid", cleanjid);
   968   xmlnode_put_attrib(y, "name", name);
   968   xmlnode_put_attrib(y, "name", name);
   975   jab_send(jc, iqn->xmldata);
   975   jab_send(jc, iqn->xmldata);
   976   iqs_del(iqn->id); // XXX
   976   iqs_del(iqn->id); // XXX
   977   g_free(cleanjid);
   977   g_free(cleanjid);
   978 }
   978 }
   979 
   979 
   980 void jb_request(const char *jid, enum iqreq_type reqtype)
   980 void jb_request(const char *fjid, enum iqreq_type reqtype)
   981 {
   981 {
   982   GSList *resources;
   982   GSList *resources;
   983   GSList *roster_elt;
   983   GSList *roster_elt;
   984   void (*request_fn)(const char *);
   984   void (*request_fn)(const char *);
   985   const char *strreqtype;
   985   const char *strreqtype;
   998   } else
   998   } else
   999     return;
   999     return;
  1000 
  1000 
  1001   // vCard request
  1001   // vCard request
  1002   if (reqtype == iqreq_vcard) {
  1002   if (reqtype == iqreq_vcard) {
  1003     char *bjid = jidtodisp(jid);
  1003     char *bjid = jidtodisp(fjid);
  1004     request_vcard(bjid);
  1004     request_vcard(bjid);
  1005     scr_LogPrint(LPRINT_NORMAL, "Sent vCard request to <%s>", bjid);
  1005     scr_LogPrint(LPRINT_NORMAL, "Sent vCard request to <%s>", bjid);
  1006     g_free(bjid);
  1006     g_free(bjid);
  1007     return;
  1007     return;
  1008   }
  1008   }
  1009 
  1009 
  1010   if (strchr(jid, JID_RESOURCE_SEPARATOR)) {
  1010   if (strchr(fjid, JID_RESOURCE_SEPARATOR)) {
  1011     // This is a full JID
  1011     // This is a full JID
  1012     (*request_fn)(jid);
  1012     (*request_fn)(fjid);
  1013     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, jid);
  1013     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, fjid);
  1014     return;
  1014     return;
  1015   }
  1015   }
  1016 
  1016 
  1017   // The resource has not been specified
  1017   // The resource has not been specified
  1018   roster_elt = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_ROOM);
  1018   roster_elt = roster_find(fjid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_ROOM);
  1019   if (!roster_elt) {
  1019   if (!roster_elt) {
  1020     scr_LogPrint(LPRINT_NORMAL, "No known resource for <%s>...", jid);
  1020     scr_LogPrint(LPRINT_NORMAL, "No known resource for <%s>...", fjid);
  1021     (*request_fn)(jid); // Let's send a request anyway...
  1021     (*request_fn)(fjid); // Let's send a request anyway...
  1022     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, jid);
  1022     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, fjid);
  1023     return;
  1023     return;
  1024   }
  1024   }
  1025 
  1025 
  1026   // Send a request to each resource
  1026   // Send a request to each resource
  1027   resources = buddy_getresources(roster_elt->data);
  1027   resources = buddy_getresources(roster_elt->data);
  1028   if (!resources) {
  1028   if (!resources) {
  1029     scr_LogPrint(LPRINT_NORMAL, "No known resource for <%s>...", jid);
  1029     scr_LogPrint(LPRINT_NORMAL, "No known resource for <%s>...", fjid);
  1030     (*request_fn)(jid); // Let's send a request anyway...
  1030     (*request_fn)(fjid); // Let's send a request anyway...
  1031     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, jid);
  1031     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, fjid);
  1032   }
  1032   }
  1033   for ( ; resources ; resources = g_slist_next(resources) ) {
  1033   for ( ; resources ; resources = g_slist_next(resources) ) {
  1034     gchar *fulljid;
  1034     gchar *fulljid;
  1035     fulljid = g_strdup_printf("%s/%s", jid, (char*)resources->data);
  1035     fulljid = g_strdup_printf("%s/%s", fjid, (char*)resources->data);
  1036     (*request_fn)(fulljid);
  1036     (*request_fn)(fulljid);
  1037     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, fulljid);
  1037     scr_LogPrint(LPRINT_NORMAL, "Sent %s request to <%s>", strreqtype, fulljid);
  1038     g_free(fulljid);
  1038     g_free(fulljid);
  1039   }
  1039   }
  1040 }
  1040 }
  1142 // allowed)
  1142 // allowed)
  1143 // ra: new role or affiliation
  1143 // ra: new role or affiliation
  1144 //     (ex. role none for kick, affil outcast for ban...)
  1144 //     (ex. role none for kick, affil outcast for ban...)
  1145 // The reason can be null
  1145 // The reason can be null
  1146 // Return 0 if everything is ok
  1146 // Return 0 if everything is ok
  1147 int jb_room_setattrib(const char *roomid, const char *jid, const char *nick,
  1147 int jb_room_setattrib(const char *roomid, const char *fjid, const char *nick,
  1148                       struct role_affil ra, const char *reason)
  1148                       struct role_affil ra, const char *reason)
  1149 {
  1149 {
  1150   xmlnode y, z;
  1150   xmlnode y, z;
  1151   eviqs *iqn;
  1151   eviqs *iqn;
  1152 
  1152 
  1153   if (!online || !roomid) return 1;
  1153   if (!online || !roomid) return 1;
  1154   if (!jid && !nick) return 1;
  1154   if (!fjid && !nick) return 1;
  1155 
  1155 
  1156   if (check_jid_syntax((char*)roomid)) {
  1156   if (check_jid_syntax((char*)roomid)) {
  1157     scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", roomid);
  1157     scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", roomid);
  1158     return 1;
  1158     return 1;
  1159   }
  1159   }
  1160   if (jid && check_jid_syntax((char*)jid)) {
  1160   if (fjid && check_jid_syntax((char*)fjid)) {
  1161     scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", jid);
  1161     scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber id", fjid);
  1162     return 1;
  1162     return 1;
  1163   }
  1163   }
  1164 
  1164 
  1165   if (ra.type == type_affil && ra.val.affil == affil_outcast && !jid)
  1165   if (ra.type == type_affil && ra.val.affil == affil_outcast && !fjid)
  1166     return 1; // Shouldn't happen (jid mandatory when banning)
  1166     return 1; // Shouldn't happen (jid mandatory when banning)
  1167 
  1167 
  1168   iqn = iqs_new(JPACKET__SET, "http://jabber.org/protocol/muc#admin",
  1168   iqn = iqs_new(JPACKET__SET, "http://jabber.org/protocol/muc#admin",
  1169                 "roleaffil", IQS_DEFAULT_TIMEOUT);
  1169                 "roleaffil", IQS_DEFAULT_TIMEOUT);
  1170   xmlnode_put_attrib(iqn->xmldata, "to", roomid);
  1170   xmlnode_put_attrib(iqn->xmldata, "to", roomid);
  1171   xmlnode_put_attrib(iqn->xmldata, "type", "set");
  1171   xmlnode_put_attrib(iqn->xmldata, "type", "set");
  1172   y = xmlnode_get_tag(iqn->xmldata, "query");
  1172   y = xmlnode_get_tag(iqn->xmldata, "query");
  1173   z = xmlnode_insert_tag(y, "item");
  1173   z = xmlnode_insert_tag(y, "item");
  1174 
  1174 
  1175   if (jid) {
  1175   if (fjid) {
  1176     xmlnode_put_attrib(z, "jid", jid);
  1176     xmlnode_put_attrib(z, "jid", fjid);
  1177   } else { // nickname
  1177   } else { // nickname
  1178     xmlnode_put_attrib(z, "nick", nick);
  1178     xmlnode_put_attrib(z, "nick", nick);
  1179   }
  1179   }
  1180 
  1180 
  1181   if (ra.type == type_affil)
  1181   if (ra.type == type_affil)
  1196 }
  1196 }
  1197 
  1197 
  1198 // Invite a user to a MUC room
  1198 // Invite a user to a MUC room
  1199 // room syntax: "room@server"
  1199 // room syntax: "room@server"
  1200 // reason can be null.
  1200 // reason can be null.
  1201 void jb_room_invite(const char *room, const char *jid, const char *reason)
  1201 void jb_room_invite(const char *room, const char *fjid, const char *reason)
  1202 {
  1202 {
  1203   xmlnode x, y, z;
  1203   xmlnode x, y, z;
  1204 
  1204 
  1205   if (!online || !room || !jid) return;
  1205   if (!online || !room || !fjid) return;
  1206 
  1206 
  1207   x = jutil_msgnew(NULL, (char*)room, NULL, NULL);
  1207   x = jutil_msgnew(NULL, (char*)room, NULL, NULL);
  1208 
  1208 
  1209   y = xmlnode_insert_tag(x, "x");
  1209   y = xmlnode_insert_tag(x, "x");
  1210   xmlnode_put_attrib(y, "xmlns", "http://jabber.org/protocol/muc#user");
  1210   xmlnode_put_attrib(y, "xmlns", "http://jabber.org/protocol/muc#user");
  1211 
  1211 
  1212   z = xmlnode_insert_tag(y, "invite");
  1212   z = xmlnode_insert_tag(y, "invite");
  1213   xmlnode_put_attrib(z, "to", jid);
  1213   xmlnode_put_attrib(z, "to", fjid);
  1214 
  1214 
  1215   if (reason) {
  1215   if (reason) {
  1216     y = xmlnode_insert_tag(z, "reason");
  1216     y = xmlnode_insert_tag(z, "reason");
  1217     xmlnode_insert_cdata(y, reason, (unsigned) -1);
  1217     xmlnode_insert_cdata(y, reason, (unsigned) -1);
  1218   }
  1218   }
  1242   }
  1242   }
  1243 
  1243 
  1244   // Walk through the storage tags
  1244   // Walk through the storage tags
  1245   x = xmlnode_get_firstchild(bookmarks);
  1245   x = xmlnode_get_firstchild(bookmarks);
  1246   for ( ; x; x = xmlnode_get_nextsibling(x)) {
  1246   for ( ; x; x = xmlnode_get_nextsibling(x)) {
  1247     const char *jid;
  1247     const char *fjid;
  1248     const char *p;
  1248     const char *p;
  1249     p = xmlnode_get_name(x);
  1249     p = xmlnode_get_name(x);
  1250     // If the current node is a conference item, see if we have to replace it.
  1250     // If the current node is a conference item, see if we have to replace it.
  1251     if (p && !strcmp(p, "conference")) {
  1251     if (p && !strcmp(p, "conference")) {
  1252       jid = xmlnode_get_attrib(x, "jid");
  1252       fjid = xmlnode_get_attrib(x, "jid");
  1253       if (!jid)
  1253       if (!fjid)
  1254         continue;
  1254         continue;
  1255       if (!strcmp(jid, roomid)) {
  1255       if (!strcmp(fjid, roomid)) {
  1256         // We've found a bookmark for this room.  Let's hide it and we'll
  1256         // We've found a bookmark for this room.  Let's hide it and we'll
  1257         // create a new one.
  1257         // create a new one.
  1258         xmlnode_hide(x);
  1258         xmlnode_hide(x);
  1259         changed = TRUE;
  1259         changed = TRUE;
  1260         break;
  1260         break;
  1352   }
  1352   }
  1353 
  1353 
  1354   // Walk through the storage rosternotes tags
  1354   // Walk through the storage rosternotes tags
  1355   x = xmlnode_get_firstchild(rosternotes);
  1355   x = xmlnode_get_firstchild(rosternotes);
  1356   for ( ; x; x = xmlnode_get_nextsibling(x)) {
  1356   for ( ; x; x = xmlnode_get_nextsibling(x)) {
  1357     const char *jid;
  1357     const char *fjid;
  1358     const char *p;
  1358     const char *p;
  1359     p = xmlnode_get_name(x);
  1359     p = xmlnode_get_name(x);
  1360     // We want a note item
  1360     // We want a note item
  1361     if (!p || strcmp(p, "note"))
  1361     if (!p || strcmp(p, "note"))
  1362       continue;
  1362       continue;
  1363     // Just in case, check the jid...
  1363     // Just in case, check the jid...
  1364     jid = xmlnode_get_attrib(x, "jid");
  1364     fjid = xmlnode_get_attrib(x, "jid");
  1365     if (jid && !strcmp(jid, barejid))  // We've found a note for this contact.
  1365     if (fjid && !strcmp(fjid, barejid)) // We've found a note for this contact.
  1366       return parse_storage_rosternote(x);
  1366       return parse_storage_rosternote(x);
  1367   }
  1367   }
  1368   return NULL;  // No note found
  1368   return NULL;  // No note found
  1369 }
  1369 }
  1370 
  1370 
  1388   }
  1388   }
  1389 
  1389 
  1390   // Walk through the storage tags
  1390   // Walk through the storage tags
  1391   x = xmlnode_get_firstchild(rosternotes);
  1391   x = xmlnode_get_firstchild(rosternotes);
  1392   for ( ; x; x = xmlnode_get_nextsibling(x)) {
  1392   for ( ; x; x = xmlnode_get_nextsibling(x)) {
  1393     const char *jid;
  1393     const char *fjid;
  1394     const char *p;
  1394     const char *p;
  1395     p = xmlnode_get_name(x);
  1395     p = xmlnode_get_name(x);
  1396     // If the current node is a conference item, see if we have to replace it.
  1396     // If the current node is a conference item, see if we have to replace it.
  1397     if (p && !strcmp(p, "note")) {
  1397     if (p && !strcmp(p, "note")) {
  1398       jid = xmlnode_get_attrib(x, "jid");
  1398       fjid = xmlnode_get_attrib(x, "jid");
  1399       if (!jid)
  1399       if (!fjid)
  1400         continue;
  1400         continue;
  1401       if (!strcmp(jid, barejid)) {
  1401       if (!strcmp(fjid, barejid)) {
  1402         // We've found a note for this jid.  Let's hide it and we'll
  1402         // We've found a note for this jid.  Let's hide it and we'll
  1403         // create a new one.
  1403         // create a new one.
  1404         cdate = xmlnode_get_attrib(x, "cdate");
  1404         cdate = xmlnode_get_attrib(x, "cdate");
  1405         xmlnode_hide(x);
  1405         xmlnode_hide(x);
  1406         changed = TRUE;
  1406         changed = TRUE;
  1490 
  1490 
  1491 static void gotmessage(char *type, const char *from, const char *body,
  1491 static void gotmessage(char *type, const char *from, const char *body,
  1492                        const char *enc, time_t timestamp,
  1492                        const char *enc, time_t timestamp,
  1493                        xmlnode xmldata_signed)
  1493                        xmlnode xmldata_signed)
  1494 {
  1494 {
  1495   char *jid;
  1495   char *bjid;
  1496   const char *rname, *s;
  1496   const char *rname, *s;
  1497   char *decrypted = NULL;
  1497   char *decrypted = NULL;
  1498 
  1498 
  1499   jid = jidtodisp(from);
  1499   bjid = jidtodisp(from);
  1500 
  1500 
  1501   rname = strchr(from, JID_RESOURCE_SEPARATOR);
  1501   rname = strchr(from, JID_RESOURCE_SEPARATOR);
  1502   if (rname) rname++;
  1502   if (rname) rname++;
  1503 
  1503 
  1504 #ifdef HAVE_GPGME
  1504 #ifdef HAVE_GPGME
  1508       body = decrypted;
  1508       body = decrypted;
  1509     }
  1509     }
  1510   }
  1510   }
  1511   // Check signature of an unencrypted message
  1511   // Check signature of an unencrypted message
  1512   if (xmldata_signed && gpg_enabled())
  1512   if (xmldata_signed && gpg_enabled())
  1513     check_signature(jid, rname, xmldata_signed, decrypted);
  1513     check_signature(bjid, rname, xmldata_signed, decrypted);
  1514 #endif
  1514 #endif
  1515 
  1515 
  1516   // Check for unexpected groupchat messages
  1516   // Check for unexpected groupchat messages
  1517   // If we receive a groupchat message from a room we're not a member of,
  1517   // If we receive a groupchat message from a room we're not a member of,
  1518   // this is probably a server issue and the best we can do is to send
  1518   // this is probably a server issue and the best we can do is to send
  1519   // a type unavailable.
  1519   // a type unavailable.
  1520   if (type && !strcmp(type, "groupchat") && !roster_getnickname(jid)) {
  1520   if (type && !strcmp(type, "groupchat") && !roster_getnickname(bjid)) {
  1521     // It shouldn't happen, probably a server issue
  1521     // It shouldn't happen, probably a server issue
  1522     GSList *room_elt;
  1522     GSList *room_elt;
  1523     char *mbuf;
  1523     char *mbuf;
  1524 
  1524 
  1525     mbuf = g_strdup_printf("Unexpected groupchat packet!");
  1525     mbuf = g_strdup_printf("Unexpected groupchat packet!");
  1526     scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
  1526     scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
  1527     scr_WriteIncomingMessage(jid, mbuf, 0, HBB_PREFIX_INFO);
  1527     scr_WriteIncomingMessage(bjid, mbuf, 0, HBB_PREFIX_INFO);
  1528     g_free(mbuf);
  1528     g_free(mbuf);
  1529 
  1529 
  1530     // Send back an unavailable packet
  1530     // Send back an unavailable packet
  1531     jb_setstatus(offline, jid, "", TRUE);
  1531     jb_setstatus(offline, bjid, "", TRUE);
  1532 
  1532 
  1533     // MUC
  1533     // MUC
  1534     // Make sure this is a room (it can be a conversion user->room)
  1534     // Make sure this is a room (it can be a conversion user->room)
  1535     room_elt = roster_find(jid, jidsearch, 0);
  1535     room_elt = roster_find(bjid, jidsearch, 0);
  1536     if (!room_elt) {
  1536     if (!room_elt) {
  1537       room_elt = roster_add_user(jid, NULL, NULL, ROSTER_TYPE_ROOM, sub_none);
  1537       room_elt = roster_add_user(bjid, NULL, NULL, ROSTER_TYPE_ROOM, sub_none);
  1538     } else {
  1538     } else {
  1539       buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
  1539       buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
  1540     }
  1540     }
  1541 
  1541 
  1542     g_free(jid);
  1542     g_free(bjid);
  1543     g_free(decrypted);
  1543     g_free(decrypted);
  1544 
  1544 
  1545     buddylist_build();
  1545     buddylist_build();
  1546     scr_DrawRoster();
  1546     scr_DrawRoster();
  1547     return;
  1547     return;
  1549 
  1549 
  1550   // We don't call the message_in hook if 'block_unsubscribed' is true and
  1550   // We don't call the message_in hook if 'block_unsubscribed' is true and
  1551   // this is a regular message from an unsubscribed user.
  1551   // this is a regular message from an unsubscribed user.
  1552   // System messages (from our server) are allowed.
  1552   // System messages (from our server) are allowed.
  1553   if (!settings_opt_get_int("block_unsubscribed") ||
  1553   if (!settings_opt_get_int("block_unsubscribed") ||
  1554       (roster_getsubscription(jid) & sub_from) ||
  1554       (roster_getsubscription(bjid) & sub_from) ||
  1555       (type && strcmp(type, "chat")) ||
  1555       (type && strcmp(type, "chat")) ||
  1556       ((s = settings_opt_get("server")) != NULL && !strcasecmp(jid, s))) {
  1556       ((s = settings_opt_get("server")) != NULL && !strcasecmp(bjid, s))) {
  1557     hk_message_in(jid, rname, timestamp, body, type,
  1557     hk_message_in(bjid, rname, timestamp, body, type,
  1558                   (decrypted ? TRUE : FALSE));
  1558                   (decrypted ? TRUE : FALSE));
  1559   } else {
  1559   } else {
  1560     scr_LogPrint(LPRINT_LOGNORM, "Blocked a message from <%s>", jid);
  1560     scr_LogPrint(LPRINT_LOGNORM, "Blocked a message from <%s>", bjid);
  1561   }
  1561   }
  1562   g_free(jid);
  1562   g_free(bjid);
  1563   g_free(decrypted);
  1563   g_free(decrypted);
  1564 }
  1564 }
  1565 
  1565 
  1566 static const char *defaulterrormsg(int code)
  1566 static const char *defaulterrormsg(int code)
  1567 {
  1567 {
  2149 void handle_state_events(char *from, xmlnode xmldata)
  2149 void handle_state_events(char *from, xmlnode xmldata)
  2150 {
  2150 {
  2151 #if defined JEP0022 || defined JEP0085
  2151 #if defined JEP0022 || defined JEP0085
  2152   xmlnode state_ns = NULL;
  2152   xmlnode state_ns = NULL;
  2153   const char *body;
  2153   const char *body;
  2154   char *rname, *jid;
  2154   char *rname, *bjid;
  2155   GSList *sl_buddy;
  2155   GSList *sl_buddy;
  2156   guint events;
  2156   guint events;
  2157   struct jep0022 *jep22 = NULL;
  2157   struct jep0022 *jep22 = NULL;
  2158   struct jep0085 *jep85 = NULL;
  2158   struct jep0085 *jep85 = NULL;
  2159   enum {
  2159   enum {
  2161     JEP_85,
  2161     JEP_85,
  2162     JEP_22
  2162     JEP_22
  2163   } which_jep = JEP_none;
  2163   } which_jep = JEP_none;
  2164 
  2164 
  2165   rname = strchr(from, JID_RESOURCE_SEPARATOR);
  2165   rname = strchr(from, JID_RESOURCE_SEPARATOR);
  2166   jid   = jidtodisp(from);
  2166   bjid  = jidtodisp(from);
  2167   sl_buddy = roster_find(jid, jidsearch, ROSTER_TYPE_USER);
  2167   sl_buddy = roster_find(bjid, jidsearch, ROSTER_TYPE_USER);
       
  2168   g_free(bjid);
  2168 
  2169 
  2169   /* XXX Actually that's wrong, since it filters out server "offline"
  2170   /* XXX Actually that's wrong, since it filters out server "offline"
  2170      messages (for JEP-0022).  This JEP is (almost) deprecated so
  2171      messages (for JEP-0022).  This JEP is (almost) deprecated so
  2171      we don't really care. */
  2172      we don't really care. */
  2172   if (!sl_buddy || !rname++) {
  2173   if (!sl_buddy || !rname++) {
  2173     g_free(jid);
       
  2174     return;
  2174     return;
  2175   }
  2175   }
  2176 
  2176 
  2177   /* Let's see chich JEP the contact uses.  If possible, we'll use
  2177   /* Let's see chich JEP the contact uses.  If possible, we'll use
  2178      JEP-85, if not we'll look for JEP-22 support. */
  2178      JEP-85, if not we'll look for JEP-22 support. */
  2193         which_jep = JEP_22;
  2193         which_jep = JEP_22;
  2194     }
  2194     }
  2195   }
  2195   }
  2196 
  2196 
  2197   if (!which_jep) { /* Sender does not use chat states */
  2197   if (!which_jep) { /* Sender does not use chat states */
  2198     g_free(jid);
       
  2199     return;
  2198     return;
  2200   }
  2199   }
  2201 
  2200 
  2202   body = xmlnode_get_tag_data(xmldata, "body");
  2201   body = xmlnode_get_tag_data(xmldata, "body");
  2203 
  2202 
  2256   }
  2255   }
  2257 
  2256 
  2258   buddy_resource_setevents(sl_buddy->data, rname, events);
  2257   buddy_resource_setevents(sl_buddy->data, rname, events);
  2259 
  2258 
  2260   update_roster = TRUE;
  2259   update_roster = TRUE;
  2261 
       
  2262   g_free(jid);
       
  2263 #endif
  2260 #endif
  2264 }
  2261 }
  2265 
  2262 
  2266 static void evscallback_subscription(eviqs *evp, guint evcontext)
  2263 static void evscallback_subscription(eviqs *evp, guint evcontext)
  2267 {
  2264 {