mcabber/src/jabglue.c
changeset 772 464be13343a9
parent 756 12dc6bdff8c1
child 774 46304b773a44
equal deleted inserted replaced
771:ce4f8a2129a4 772:464be13343a9
    94 }
    94 }
    95 
    95 
    96 jconn jb_connect(const char *jid, const char *server, unsigned int port,
    96 jconn jb_connect(const char *jid, const char *server, unsigned int port,
    97                  int ssl, const char *pass)
    97                  int ssl, const char *pass)
    98 {
    98 {
    99   char *utf8_jid;
       
   100   if (!port) {
    99   if (!port) {
   101     if (ssl)
   100     if (ssl)
   102       port = JABBERSSLPORT;
   101       port = JABBERSSLPORT;
   103     else
   102     else
   104       port = JABBERPORT;
   103       port = JABBERPORT;
   105   }
   104   }
   106 
   105 
   107   jb_disconnect();
   106   jb_disconnect();
   108 
   107 
   109   utf8_jid = to_utf8(jid);
   108   if (!jid) return jc;
   110   if (!utf8_jid) return jc;
   109 
   111 
   110   jc = jab_new((char*)jid, (char*)pass, (char*)server, port, ssl);
   112   jc = jab_new(utf8_jid, (char*)pass, (char*)server, port, ssl);
       
   113   g_free(utf8_jid);
       
   114 
   111 
   115   /* These 3 functions can deal with a NULL jc, no worry... */
   112   /* These 3 functions can deal with a NULL jc, no worry... */
   116   jab_logger(jc, logger);
   113   jab_logger(jc, logger);
   117   jab_packet_handler(jc, &packethandler);
   114   jab_packet_handler(jc, &packethandler);
   118   jab_state_handler(jc, &statehandler);
   115   jab_state_handler(jc, &statehandler);
   266 static xmlnode presnew(enum imstatus st, const char *recipient,
   263 static xmlnode presnew(enum imstatus st, const char *recipient,
   267                        const char *msg)
   264                        const char *msg)
   268 {
   265 {
   269   unsigned int prio;
   266   unsigned int prio;
   270   xmlnode x;
   267   xmlnode x;
   271   gchar *utf8_recipient = to_utf8(recipient);
       
   272 
   268 
   273   x = jutil_presnew(JPACKET__UNKNOWN, 0, 0);
   269   x = jutil_presnew(JPACKET__UNKNOWN, 0, 0);
   274 
   270 
   275   if (utf8_recipient) {
   271   if (recipient) {
   276     xmlnode_put_attrib(x, "to", utf8_recipient);
   272     xmlnode_put_attrib(x, "to", recipient);
   277     g_free(utf8_recipient);
       
   278   }
   273   }
   279 
   274 
   280   switch(st) {
   275   switch(st) {
   281     case away:
   276     case away:
   282         xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "away",
   277         xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "away",
   316     snprintf(strprio, 8, "%u", prio);
   311     snprintf(strprio, 8, "%u", prio);
   317     xmlnode_insert_cdata(xmlnode_insert_tag(x, "priority"),
   312     xmlnode_insert_cdata(xmlnode_insert_tag(x, "priority"),
   318                          strprio, (unsigned) -1);
   313                          strprio, (unsigned) -1);
   319   }
   314   }
   320 
   315 
   321   if (msg) {
   316   if (msg)
   322     gchar *utf8_msg = to_utf8(msg);
   317     xmlnode_insert_cdata(xmlnode_insert_tag(x, "status"), msg, (unsigned) -1);
   323     xmlnode_insert_cdata(xmlnode_insert_tag(x, "status"), utf8_msg,
       
   324                          (unsigned) -1);
       
   325     g_free(utf8_msg);
       
   326   }
       
   327 
   318 
   328   return x;
   319   return x;
   329 }
   320 }
   330 
   321 
   331 void jb_setstatus(enum imstatus st, const char *recipient, const char *msg)
   322 void jb_setstatus(enum imstatus st, const char *recipient, const char *msg)
   391 void jb_send_msg(const char *jid, const char *text, int type,
   382 void jb_send_msg(const char *jid, const char *text, int type,
   392                  const char *subject)
   383                  const char *subject)
   393 {
   384 {
   394   xmlnode x;
   385   xmlnode x;
   395   gchar *strtype;
   386   gchar *strtype;
   396   gchar *utf8_jid;
       
   397   gchar *buffer;
       
   398 
   387 
   399   if (!online) return;
   388   if (!online) return;
   400 
   389 
   401   if (type == ROSTER_TYPE_ROOM)
   390   if (type == ROSTER_TYPE_ROOM)
   402     strtype = TMSG_GROUPCHAT;
   391     strtype = TMSG_GROUPCHAT;
   403   else
   392   else
   404     strtype = TMSG_CHAT;
   393     strtype = TMSG_CHAT;
   405 
   394 
   406   buffer = to_utf8(text);
   395   x = jutil_msgnew(strtype, (char*)jid, NULL, (char*)text);
   407   utf8_jid = to_utf8(jid); // Resource can require UTF-8
       
   408 
       
   409   x = jutil_msgnew(strtype, utf8_jid, NULL, (char*)buffer);
       
   410   if (subject) {
   396   if (subject) {
   411     xmlnode y;
   397     xmlnode y;
   412     char *bs = to_utf8(subject);
       
   413     y = xmlnode_insert_tag(x, "subject");
   398     y = xmlnode_insert_tag(x, "subject");
   414     xmlnode_insert_cdata(y, bs, (unsigned) -1);
   399     xmlnode_insert_cdata(y, subject, (unsigned) -1);
   415     if (bs) g_free(bs);
       
   416   }
   400   }
   417   jab_send(jc, x);
   401   jab_send(jc, x);
   418   xmlnode_free(x);
   402   xmlnode_free(x);
   419 
       
   420   if (buffer) g_free(buffer);
       
   421   if (utf8_jid) g_free(utf8_jid);
       
   422 
   403 
   423   jb_reset_keepalive();
   404   jb_reset_keepalive();
   424 }
   405 }
   425 
   406 
   426 //  jb_subscr_send_auth(jid)
   407 //  jb_subscr_send_auth(jid)
   427 // Allow jid to receive our presence updates
   408 // Allow jid to receive our presence updates
   428 void jb_subscr_send_auth(const char *jid)
   409 void jb_subscr_send_auth(const char *jid)
   429 {
   410 {
   430   xmlnode x;
   411   xmlnode x;
   431   char *utf8_jid = to_utf8(jid);
   412 
   432 
   413   x = jutil_presnew(JPACKET__SUBSCRIBED, (char *)jid, NULL);
   433   x = jutil_presnew(JPACKET__SUBSCRIBED, utf8_jid, NULL);
       
   434   jab_send(jc, x);
   414   jab_send(jc, x);
   435   xmlnode_free(x);
   415   xmlnode_free(x);
   436   g_free(utf8_jid);
       
   437 }
   416 }
   438 
   417 
   439 //  jb_subscr_cancel_auth(jid)
   418 //  jb_subscr_cancel_auth(jid)
   440 // Cancel jid's subscription to our presence updates
   419 // Cancel jid's subscription to our presence updates
   441 void jb_subscr_cancel_auth(const char *jid)
   420 void jb_subscr_cancel_auth(const char *jid)
   442 {
   421 {
   443   xmlnode x;
   422   xmlnode x;
   444   char *utf8_jid = to_utf8(jid);
   423 
   445 
   424   x = jutil_presnew(JPACKET__UNSUBSCRIBED, (char *)jid, NULL);
   446   x = jutil_presnew(JPACKET__UNSUBSCRIBED, utf8_jid, NULL);
       
   447   jab_send(jc, x);
   425   jab_send(jc, x);
   448   xmlnode_free(x);
   426   xmlnode_free(x);
   449   g_free(utf8_jid);
       
   450 }
   427 }
   451 
   428 
   452 //  jb_subscr_request_auth(jid)
   429 //  jb_subscr_request_auth(jid)
   453 // Request a subscription to jid's presence updates
   430 // Request a subscription to jid's presence updates
   454 void jb_subscr_request_auth(const char *jid)
   431 void jb_subscr_request_auth(const char *jid)
   455 {
   432 {
   456   xmlnode x;
   433   xmlnode x;
   457   char *utf8_jid = to_utf8(jid);
   434 
   458 
   435   x = jutil_presnew(JPACKET__SUBSCRIBE, (char *)jid, NULL);
   459   x = jutil_presnew(JPACKET__SUBSCRIBE, utf8_jid, NULL);
       
   460   jab_send(jc, x);
   436   jab_send(jc, x);
   461   xmlnode_free(x);
   437   xmlnode_free(x);
   462   g_free(utf8_jid);
       
   463 }
   438 }
   464 
   439 
   465 // Note: the caller should check the jid is correct
   440 // Note: the caller should check the jid is correct
   466 void jb_addbuddy(const char *jid, const char *name, const char *group)
   441 void jb_addbuddy(const char *jid, const char *name, const char *group)
   467 {
   442 {
   479   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   454   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   480   y = xmlnode_insert_tag(xmlnode_get_tag(iqn->xmldata, "query"), "item");
   455   y = xmlnode_insert_tag(xmlnode_get_tag(iqn->xmldata, "query"), "item");
   481 
   456 
   482   xmlnode_put_attrib(y, "jid", cleanjid);
   457   xmlnode_put_attrib(y, "jid", cleanjid);
   483 
   458 
   484   if (name) {
   459   if (name)
   485     gchar *name_utf8 = to_utf8(name);
   460     xmlnode_put_attrib(y, "name", name);
   486     xmlnode_put_attrib(y, "name", name_utf8);
       
   487     g_free(name_utf8);
       
   488   }
       
   489 
   461 
   490   if (group) {
   462   if (group) {
   491     char *group_utf8 = to_utf8(group);
       
   492     z = xmlnode_insert_tag(y, "group");
   463     z = xmlnode_insert_tag(y, "group");
   493     xmlnode_insert_cdata(z, group_utf8, (unsigned) -1);
   464     xmlnode_insert_cdata(z, group, (unsigned) -1);
   494     g_free(group_utf8);
       
   495   }
   465   }
   496 
   466 
   497   jab_send(jc, iqn->xmldata);
   467   jab_send(jc, iqn->xmldata);
   498   iqs_del(iqn->id); // XXX
   468   iqs_del(iqn->id); // XXX
   499 
   469 
   555 void jb_updatebuddy(const char *jid, const char *name, const char *group)
   525 void jb_updatebuddy(const char *jid, const char *name, const char *group)
   556 {
   526 {
   557   xmlnode y;
   527   xmlnode y;
   558   eviqs *iqn;
   528   eviqs *iqn;
   559   char *cleanjid;
   529   char *cleanjid;
   560   gchar *name_utf8;
       
   561 
   530 
   562   if (!online) return;
   531   if (!online) return;
   563 
   532 
   564   // XXX We should check name's and group's correctness
   533   // XXX We should check name's and group's correctness
   565 
   534 
   566   cleanjid = jidtodisp(jid);
   535   cleanjid = jidtodisp(jid);
   567   name_utf8 = to_utf8(name);
       
   568 
   536 
   569   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   537   iqn = iqs_new(JPACKET__SET, NS_ROSTER, NULL, IQS_DEFAULT_TIMEOUT);
   570   y = xmlnode_insert_tag(xmlnode_get_tag(iqn->xmldata, "query"), "item");
   538   y = xmlnode_insert_tag(xmlnode_get_tag(iqn->xmldata, "query"), "item");
   571   xmlnode_put_attrib(y, "jid", cleanjid);
   539   xmlnode_put_attrib(y, "jid", cleanjid);
   572   xmlnode_put_attrib(y, "name", name_utf8);
   540   xmlnode_put_attrib(y, "name", name);
   573 
   541 
   574   if (group) {
   542   if (group) {
   575     gchar *group_utf8 = to_utf8(group);
       
   576     y = xmlnode_insert_tag(y, "group");
   543     y = xmlnode_insert_tag(y, "group");
   577     xmlnode_insert_cdata(y, group_utf8, (unsigned) -1);
   544     xmlnode_insert_cdata(y, group, (unsigned) -1);
   578     g_free(group_utf8);
       
   579   }
   545   }
   580 
   546 
   581   jab_send(jc, iqn->xmldata);
   547   jab_send(jc, iqn->xmldata);
   582   iqs_del(iqn->id); // XXX
   548   iqs_del(iqn->id); // XXX
   583   g_free(name_utf8);
       
   584   g_free(cleanjid);
   549   g_free(cleanjid);
   585 }
   550 }
   586 
   551 
   587 void jb_request(const char *jid, enum iqreq_type reqtype)
   552 void jb_request(const char *jid, enum iqreq_type reqtype)
   588 {
   553 {
   709 
   674 
   710   if (venue && *venue)
   675   if (venue && *venue)
   711     xmlnode_put_attrib(z, "jid", venue);
   676     xmlnode_put_attrib(z, "jid", venue);
   712 
   677 
   713   if (reason) {
   678   if (reason) {
   714     gchar *utf8_reason = to_utf8(reason);
       
   715     y = xmlnode_insert_tag(z, "reason");
   679     y = xmlnode_insert_tag(z, "reason");
   716     xmlnode_insert_cdata(y, utf8_reason, (unsigned) -1);
   680     xmlnode_insert_cdata(y, reason, (unsigned) -1);
   717     g_free(utf8_reason);
       
   718   }
   681   }
   719 
   682 
   720   jab_send(jc, iqn->xmldata);
   683   jab_send(jc, iqn->xmldata);
   721   iqs_del(iqn->id); // XXX
   684   iqs_del(iqn->id); // XXX
   722   jb_reset_keepalive();
   685   jb_reset_keepalive();
   757   xmlnode_put_attrib(iqn->xmldata, "type", "set");
   720   xmlnode_put_attrib(iqn->xmldata, "type", "set");
   758   y = xmlnode_get_tag(iqn->xmldata, "query");
   721   y = xmlnode_get_tag(iqn->xmldata, "query");
   759   z = xmlnode_insert_tag(y, "item");
   722   z = xmlnode_insert_tag(y, "item");
   760 
   723 
   761   if (jid) {
   724   if (jid) {
   762     gchar *utf8_jid = to_utf8(jid);
   725     xmlnode_put_attrib(z, "jid", jid);
   763     xmlnode_put_attrib(z, "jid", utf8_jid);
   726   } else { // nickname
   764     if (utf8_jid) g_free(utf8_jid);
   727     xmlnode_put_attrib(z, "nick", nick);
   765   } else { // nick
       
   766     gchar *utf8_nickname = to_utf8(nick);
       
   767     xmlnode_put_attrib(z, "nick", utf8_nickname);
       
   768     g_free(utf8_nickname);
       
   769   }
   728   }
   770 
   729 
   771   if (ra.type == type_affil)
   730   if (ra.type == type_affil)
   772     xmlnode_put_attrib(z, "affiliation", straffil[ra.val.affil]);
   731     xmlnode_put_attrib(z, "affiliation", straffil[ra.val.affil]);
   773   else if (ra.type == type_role)
   732   else if (ra.type == type_role)
   774     xmlnode_put_attrib(z, "role", strrole[ra.val.role]);
   733     xmlnode_put_attrib(z, "role", strrole[ra.val.role]);
   775 
   734 
   776   if (reason) {
   735   if (reason) {
   777     gchar *utf8_reason = to_utf8(reason);
       
   778     y = xmlnode_insert_tag(z, "reason");
   736     y = xmlnode_insert_tag(z, "reason");
   779     xmlnode_insert_cdata(y, utf8_reason, (unsigned) -1);
   737     xmlnode_insert_cdata(y, reason, (unsigned) -1);
   780     g_free(utf8_reason);
       
   781   }
   738   }
   782 
   739 
   783   jab_send(jc, iqn->xmldata);
   740   jab_send(jc, iqn->xmldata);
   784   iqs_del(iqn->id); // XXX
   741   iqs_del(iqn->id); // XXX
   785   jb_reset_keepalive();
   742   jb_reset_keepalive();
   791 // room syntax: "room@server"
   748 // room syntax: "room@server"
   792 // reason can be null.
   749 // reason can be null.
   793 void jb_room_invite(const char *room, const char *jid, const char *reason)
   750 void jb_room_invite(const char *room, const char *jid, const char *reason)
   794 {
   751 {
   795   xmlnode x, y, z;
   752   xmlnode x, y, z;
   796   gchar *utf8_jid;
       
   797 
   753 
   798   if (!online || !room || !jid) return;
   754   if (!online || !room || !jid) return;
   799 
   755 
   800   x = jutil_msgnew(NULL, (char*)room, NULL, NULL);
   756   x = jutil_msgnew(NULL, (char*)room, NULL, NULL);
   801 
   757 
   802   y = xmlnode_insert_tag(x, "x");
   758   y = xmlnode_insert_tag(x, "x");
   803   xmlnode_put_attrib(y, "xmlns", "http://jabber.org/protocol/muc#user");
   759   xmlnode_put_attrib(y, "xmlns", "http://jabber.org/protocol/muc#user");
   804 
   760 
   805   utf8_jid = to_utf8(jid); // Resource can require UTF-8
       
   806   z = xmlnode_insert_tag(y, "invite");
   761   z = xmlnode_insert_tag(y, "invite");
   807   xmlnode_put_attrib(z, "to", utf8_jid);
   762   xmlnode_put_attrib(z, "to", jid);
   808   if (utf8_jid) g_free(utf8_jid);
       
   809 
   763 
   810   if (reason) {
   764   if (reason) {
   811     gchar *utf8_reason = to_utf8(reason);
       
   812     y = xmlnode_insert_tag(z, "reason");
   765     y = xmlnode_insert_tag(z, "reason");
   813     xmlnode_insert_cdata(y, utf8_reason, (unsigned) -1);
   766     xmlnode_insert_cdata(y, reason, (unsigned) -1);
   814     g_free(utf8_reason);
       
   815   }
   767   }
   816 
   768 
   817   jab_send(jc, x);
   769   jab_send(jc, x);
   818   xmlnode_free(x);
   770   xmlnode_free(x);
   819   jb_reset_keepalive();
   771   jb_reset_keepalive();
   822 static void gotmessage(char *type, const char *from, const char *body,
   774 static void gotmessage(char *type, const char *from, const char *body,
   823                        const char *enc, time_t timestamp)
   775                        const char *enc, time_t timestamp)
   824 {
   776 {
   825   char *jid;
   777   char *jid;
   826   const char *rname;
   778   const char *rname;
   827   gchar *buffer = from_utf8(body);
       
   828 
   779 
   829   jid = jidtodisp(from);
   780   jid = jidtodisp(from);
   830 
       
   831   if (!buffer && body) {
       
   832     scr_LogPrint(LPRINT_NORMAL, "Decoding of message from <%s> has failed",
       
   833                  from);
       
   834     scr_LogPrint(LPRINT_LOG, "Decoding of message from <%s> has failed: %s",
       
   835                  from, body);
       
   836     scr_WriteIncomingMessage(jid, "Cannot display message: "
       
   837                              "UTF-8 conversion failure",
       
   838                              0, HBB_PREFIX_ERR | HBB_PREFIX_IN);
       
   839     g_free(jid);
       
   840     return;
       
   841   }
       
   842 
   781 
   843   rname = strchr(from, '/');
   782   rname = strchr(from, '/');
   844   if (rname) rname++;
   783   if (rname) rname++;
   845   hk_message_in(jid, rname, timestamp, buffer, type);
   784   hk_message_in(jid, rname, timestamp, body, type);
   846   g_free(jid);
   785   g_free(jid);
   847   g_free(buffer);
       
   848 }
   786 }
   849 
   787 
   850 static const char *defaulterrormsg(int code)
   788 static const char *defaulterrormsg(int code)
   851 {
   789 {
   852   const char *desc;
   790   const char *desc;
   922   s = xmlnode_get_data(x);
   860   s = xmlnode_get_data(x);
   923   if (s && *s) desc = s;
   861   if (s && *s) desc = s;
   924 
   862 
   925   // And sometimes there is a text message
   863   // And sometimes there is a text message
   926   s = xmlnode_get_tag_data(x, "text");
   864   s = xmlnode_get_tag_data(x, "text");
   927   if (s && *s) desc = s; // FIXME utf8??
   865   if (s && *s) desc = s;
   928 
   866 
   929   scr_LogPrint(LPRINT_LOGNORM, "Error code from server: %d %s", code, desc);
   867   scr_LogPrint(LPRINT_LOGNORM, "Error code from server: %d %s", code, desc);
   930 }
   868 }
   931 
   869 
   932 static void statehandler(jconn conn, int state)
   870 static void statehandler(jconn conn, int state)
  1075   }
  1013   }
  1076 
  1014 
  1077   // Check for nickname change
  1015   // Check for nickname change
  1078   if (statuscode == 303 && mbnick) {
  1016   if (statuscode == 303 && mbnick) {
  1079     gchar *mbuf;
  1017     gchar *mbuf;
  1080     gchar *newname_noutf8 = from_utf8(mbnick);
  1018     mbuf = g_strdup_printf("%s is now known as %s", rname, mbnick);
  1081     if (!newname_noutf8)
       
  1082       scr_LogPrint(LPRINT_LOG, "Decoding of new nickname has failed: %s",
       
  1083                    mbnick);
       
  1084     mbuf = g_strdup_printf("%s is now known as %s", rname,
       
  1085                            (newname_noutf8 ? newname_noutf8 : "(?)"));
       
  1086     scr_WriteIncomingMessage(roomjid, mbuf, usttime,
  1019     scr_WriteIncomingMessage(roomjid, mbuf, usttime,
  1087                              HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
  1020                              HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
  1088     if (log_muc_conf) hlog_write_message(roomjid, 0, FALSE, mbuf);
  1021     if (log_muc_conf) hlog_write_message(roomjid, 0, FALSE, mbuf);
  1089     g_free(mbuf);
  1022     g_free(mbuf);
  1090     if (newname_noutf8) {
  1023     buddy_resource_setname(room_elt->data, rname, mbnick);
  1091       buddy_resource_setname(room_elt->data, rname, newname_noutf8);
  1024     // Maybe it's _our_ nickname...
  1092       m = buddy_getnickname(room_elt->data);
  1025     m = buddy_getnickname(room_elt->data);
  1093       if (m && !strcmp(rname, m))
  1026     if (m && !strcmp(rname, m))
  1094         buddy_setnickname(room_elt->data, newname_noutf8);
  1027       buddy_setnickname(room_elt->data, mbnick);
  1095       g_free(newname_noutf8);
       
  1096     }
       
  1097   }
  1028   }
  1098 
  1029 
  1099   // Check for departure/arrival
  1030   // Check for departure/arrival
  1100   if (!mbnick && mbrole == role_none) {
  1031   if (!mbnick && mbrole == role_none) {
  1101     gchar *mbuf;
  1032     gchar *mbuf;
  1123     // The message depends on _who_ left, and _how_
  1054     // The message depends on _who_ left, and _how_
  1124     if (how) {
  1055     if (how) {
  1125       gchar *mbuf_end;
  1056       gchar *mbuf_end;
  1126       // Forced leave
  1057       // Forced leave
  1127       if (actorjid) {
  1058       if (actorjid) {
  1128         gchar *rsn_noutf8 = from_utf8(reason);
       
  1129         if (!rsn_noutf8 && reason) {
       
  1130           scr_LogPrint(LPRINT_NORMAL, "UTF-8 decoding of reason has failed");
       
  1131           scr_LogPrint(LPRINT_LOG, "UTF-8 decoding of reason has failed: %s",
       
  1132                        reason);
       
  1133         }
       
  1134         mbuf_end = g_strdup_printf("%s from %s by <%s>.\nReason: %s",
  1059         mbuf_end = g_strdup_printf("%s from %s by <%s>.\nReason: %s",
  1135                                    (how == ban ? "banned" : "kicked"),
  1060                                    (how == ban ? "banned" : "kicked"),
  1136                                    roomjid, actorjid,
  1061                                    roomjid, actorjid, reason);
  1137                                    (rsn_noutf8 ? rsn_noutf8 : "None given"));
       
  1138         if (rsn_noutf8)
       
  1139           g_free(rsn_noutf8);
       
  1140       } else {
  1062       } else {
  1141         mbuf_end = g_strdup_printf("%s from %s.",
  1063         mbuf_end = g_strdup_printf("%s from %s.",
  1142                                    (how == ban ? "banned" : "kicked"),
  1064                                    (how == ban ? "banned" : "kicked"),
  1143                                    roomjid);
  1065                                    roomjid);
  1144       }
  1066       }
  1151     } else {
  1073     } else {
  1152       // Natural leave
  1074       // Natural leave
  1153       if (we_left) {
  1075       if (we_left) {
  1154         xmlnode destroynode = xmlnode_get_tag(xmldata, "destroy");
  1076         xmlnode destroynode = xmlnode_get_tag(xmldata, "destroy");
  1155         if (destroynode) {
  1077         if (destroynode) {
  1156           gchar *rsn_noutf8 = NULL;
  1078           if ((reason = xmlnode_get_tag_data(destroynode, "reason"))) {
  1157           if ((reason = xmlnode_get_tag_data(destroynode, "reason")))
       
  1158             rsn_noutf8 = from_utf8(reason);
       
  1159           if (rsn_noutf8) {
       
  1160             mbuf = g_strdup_printf("You have left %s, "
  1079             mbuf = g_strdup_printf("You have left %s, "
  1161                                    "the room has been destroyed: %s",
  1080                                    "the room has been destroyed: %s",
  1162                                    roomjid, rsn_noutf8);
  1081                                    roomjid, reason);
  1163             g_free(rsn_noutf8);
       
  1164           } else {
  1082           } else {
  1165             mbuf = g_strdup_printf("You have left %s, "
  1083             mbuf = g_strdup_printf("You have left %s, "
  1166                                    "the room has been destroyed", roomjid);
  1084                                    "the room has been destroyed", roomjid);
  1167           }
  1085           }
  1168         } else {
  1086         } else {
  1194 
  1112 
  1195     if (!ournick) {
  1113     if (!ournick) {
  1196       // I think it shouldn't happen, but let's put a warning for a while...
  1114       // I think it shouldn't happen, but let's put a warning for a while...
  1197       mbuf = g_strdup_printf("MUC ERR: you have no nickname, "
  1115       mbuf = g_strdup_printf("MUC ERR: you have no nickname, "
  1198                              "please send a bug report!");
  1116                              "please send a bug report!");
  1199       scr_LogPrint(LPRINT_LOGNORM, mbuf);
  1117       scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
  1200       scr_WriteIncomingMessage(roomjid, mbuf, 0, HBB_PREFIX_INFO);
  1118       scr_WriteIncomingMessage(roomjid, mbuf, 0, HBB_PREFIX_INFO);
  1201       g_free(mbuf);
  1119       g_free(mbuf);
  1202       buddylist_build();
  1120       buddylist_build();
  1203       scr_DrawRoster();
  1121       scr_DrawRoster();
  1204       return;
  1122       return;
  1243     }
  1161     }
  1244   }
  1162   }
  1245 
  1163 
  1246   // Update room member status
  1164   // Update room member status
  1247   if (rname) {
  1165   if (rname) {
  1248     gchar *mbrjid_noutf8 = from_utf8(mbjid);
       
  1249     roster_setstatus(roomjid, rname, bpprio, ust, ustmsg, usttime,
  1166     roster_setstatus(roomjid, rname, bpprio, ust, ustmsg, usttime,
  1250                      mbrole, mbaffil, mbrjid_noutf8);
  1167                      mbrole, mbaffil, mbjid);
  1251     if (mbrjid_noutf8)
       
  1252       g_free(mbrjid_noutf8);
       
  1253   } else
  1168   } else
  1254     scr_LogPrint(LPRINT_LOGNORM, "MUC DBG: no rname!"); /* DBG */
  1169     scr_LogPrint(LPRINT_LOGNORM, "MUC DBG: no rname!"); /* DBG */
  1255 
  1170 
  1256   buddylist_build();
  1171   buddylist_build();
  1257   scr_DrawRoster();
  1172   scr_DrawRoster();
  1312   }
  1227   }
  1313 
  1228 
  1314   if (type && !strcmp(type, "unavailable"))
  1229   if (type && !strcmp(type, "unavailable"))
  1315     ust = offline;
  1230     ust = offline;
  1316 
  1231 
  1317   ustmsg = NULL;
  1232   ustmsg = xmlnode_get_tag_data(xmldata, "status");
  1318   p = xmlnode_get_tag_data(xmldata, "status");
       
  1319   if (p) {
       
  1320     ustmsg = from_utf8(p);
       
  1321     if (!ustmsg)
       
  1322       scr_LogPrint(LPRINT_LOG,
       
  1323                    "Decoding of status message of <%s> has failed: %s",
       
  1324                    from, p);
       
  1325   }
       
  1326 
  1233 
  1327   // Timestamp?
  1234   // Timestamp?
  1328   timestamp = xml_get_timestamp(xmldata);
  1235   timestamp = xml_get_timestamp(xmldata);
  1329 
  1236 
  1330   if (muc_packet) {
  1237   if (muc_packet) {
  1340         (!ustmsg && m && m[0]) || (ustmsg && (!m || strcmp(ustmsg, m))))
  1247         (!ustmsg && m && m[0]) || (ustmsg && (!m || strcmp(ustmsg, m))))
  1341       hk_statuschange(r, rname, bpprio, timestamp, ust, ustmsg);
  1248       hk_statuschange(r, rname, bpprio, timestamp, ust, ustmsg);
  1342   }
  1249   }
  1343 
  1250 
  1344   g_free(r);
  1251   g_free(r);
  1345   if (ustmsg) g_free(ustmsg);
       
  1346 }
  1252 }
  1347 
  1253 
  1348 static void handle_packet_message(jconn conn, char *type, char *from,
  1254 static void handle_packet_message(jconn conn, char *type, char *from,
  1349                                   xmlnode xmldata)
  1255                                   xmlnode xmldata)
  1350 {
  1256 {
  1360   p = xmlnode_get_tag_data(xmldata, "subject");
  1266   p = xmlnode_get_tag_data(xmldata, "subject");
  1361   if (p != NULL) {
  1267   if (p != NULL) {
  1362     if (type && !strcmp(type, TMSG_GROUPCHAT)) {  // Room topic
  1268     if (type && !strcmp(type, TMSG_GROUPCHAT)) {  // Room topic
  1363       GSList *roombuddy;
  1269       GSList *roombuddy;
  1364       gchar *mbuf;
  1270       gchar *mbuf;
  1365       gchar *subj_noutf8 = from_utf8(p);
  1271       gchar *subj = p;
  1366       if (!subj_noutf8)
       
  1367         scr_LogPrint(LPRINT_LOG,
       
  1368                      "Decoding of room topic has failed: %s", p);
       
  1369       // Get the room (s) and the nickname (r)
  1272       // Get the room (s) and the nickname (r)
  1370       s = g_strdup(from);
  1273       s = g_strdup(from);
  1371       r = strchr(s, '/');
  1274       r = strchr(s, '/');
  1372       if (r) *r++ = 0;
  1275       if (r) *r++ = 0;
  1373       else   r = s;
  1276       else   r = s;
  1374       // Set the new topic
  1277       // Set the new topic
  1375       roombuddy = roster_find(s, jidsearch, 0);
  1278       roombuddy = roster_find(s, jidsearch, 0);
  1376       if (roombuddy)
  1279       if (roombuddy)
  1377         buddy_settopic(roombuddy->data, subj_noutf8);
  1280         buddy_settopic(roombuddy->data, subj);
  1378       // Display inside the room window
  1281       // Display inside the room window
  1379       if (r == s) {
  1282       if (r == s) {
  1380         // No specific resource (this is certainly history)
  1283         // No specific resource (this is certainly history)
  1381         mbuf = g_strdup_printf("The topic has been set to: %s",
  1284         mbuf = g_strdup_printf("The topic has been set to: %s", subj);
  1382                                (subj_noutf8 ? subj_noutf8 : "(?)"));
       
  1383       } else {
  1285       } else {
  1384         mbuf = g_strdup_printf("%s has set the topic to: %s", r,
  1286         mbuf = g_strdup_printf("%s has set the topic to: %s", r, subj);
  1385                                (subj_noutf8 ? subj_noutf8 : "(?)"));
       
  1386       }
  1287       }
  1387       scr_WriteIncomingMessage(s, mbuf, 0,
  1288       scr_WriteIncomingMessage(s, mbuf, 0,
  1388                                HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
  1289                                HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG);
  1389       if (settings_opt_get_int("log_muc_conf"))
  1290       if (settings_opt_get_int("log_muc_conf"))
  1390         hlog_write_message(s, 0, FALSE, mbuf);
  1291         hlog_write_message(s, 0, FALSE, mbuf);
  1391       if (subj_noutf8) g_free(subj_noutf8);
       
  1392       g_free(s);
  1292       g_free(s);
  1393       g_free(mbuf);
  1293       g_free(mbuf);
  1394       // The topic is displayed in the chat status line, so refresh now.
  1294       // The topic is displayed in the chat status line, so refresh now.
  1395       scr_UpdateChatStatus(TRUE);
  1295       scr_UpdateChatStatus(TRUE);
  1396     } else {                                      // Chat message
  1296     } else {                                      // Chat message
  1488     scr_WriteIncomingMessage(r, buf, 0, HBB_PREFIX_INFO);
  1388     scr_WriteIncomingMessage(r, buf, 0, HBB_PREFIX_INFO);
  1489     scr_LogPrint(LPRINT_LOGNORM, "%s", buf);
  1389     scr_LogPrint(LPRINT_LOGNORM, "%s", buf);
  1490     g_free(buf);
  1390     g_free(buf);
  1491 
  1391 
  1492     if (msg) {
  1392     if (msg) {
  1493       char *msg_noutf8 = from_utf8(msg);
  1393       buf = g_strdup_printf("<%s> said: %s", from, msg);
  1494       if (msg_noutf8) {
  1394       scr_WriteIncomingMessage(r, buf, 0, HBB_PREFIX_INFO);
  1495         buf = g_strdup_printf("<%s> said: %s", from, msg_noutf8);
  1395       replace_nl_with_dots(buf);
  1496         scr_WriteIncomingMessage(r, buf, 0, HBB_PREFIX_INFO);
  1396       scr_LogPrint(LPRINT_LOGNORM, "%s", buf);
  1497         replace_nl_with_dots(buf);
  1397       g_free(buf);
  1498         scr_LogPrint(LPRINT_LOGNORM, buf);
       
  1499         g_free(buf);
       
  1500         g_free(msg_noutf8);
       
  1501       }
       
  1502     }
  1398     }
  1503 
  1399 
  1504     // Create a new event item
  1400     // Create a new event item
  1505     evn = evs_new(EVS_TYPE_SUBSCRIPTION, EVS_MAX_TIMEOUT);
  1401     evn = evs_new(EVS_TYPE_SUBSCRIPTION, EVS_MAX_TIMEOUT);
  1506     if (evn) {
  1402     if (evn) {
  1546   g_free(r);
  1442   g_free(r);
  1547 }
  1443 }
  1548 
  1444 
  1549 static void packethandler(jconn conn, jpacket packet)
  1445 static void packethandler(jconn conn, jpacket packet)
  1550 {
  1446 {
  1551   char *p, *r, *s;
  1447   char *p;
       
  1448   /*
       
  1449   char *r, *s;
  1552   const char *m;
  1450   const char *m;
       
  1451   */
  1553   char *from=NULL, *type=NULL;
  1452   char *from=NULL, *type=NULL;
  1554 
  1453 
  1555   jb_reset_keepalive(); // reset keepalive timeout
  1454   jb_reset_keepalive(); // reset keepalive timeout
  1556   jpacket_reset(packet);
  1455   jpacket_reset(packet);
  1557 
  1456 
  1562 
  1461 
  1563   p = xmlnode_get_attrib(packet->x, "type");
  1462   p = xmlnode_get_attrib(packet->x, "type");
  1564   if (p) type = p;
  1463   if (p) type = p;
  1565 
  1464 
  1566   p = xmlnode_get_attrib(packet->x, "from");
  1465   p = xmlnode_get_attrib(packet->x, "from");
  1567   if (p) {   // Convert from UTF8
  1466   if (p) from = p;
  1568     // We need to be careful because from_utf8() can fail on some chars
       
  1569     // Thus we only convert the resource part
       
  1570     from = g_new0(char, strlen(p)+1);
       
  1571     strcpy(from, p);
       
  1572     r = strchr(from, '/');
       
  1573     m = strchr(p, '/');
       
  1574     if (m++) {
       
  1575       s = from_utf8(m);
       
  1576       if (s) {
       
  1577         // In some cases the allocated memory size could be too small because
       
  1578         // when chars cannot be converted strings like "\uxxxx" or "\Uxxxxyyyy"
       
  1579         // are used.
       
  1580         if (strlen(r+1) < strlen(s)) {
       
  1581           from = g_realloc(from, 1+m-p+strlen(s));
       
  1582           r = strchr(from, '/');
       
  1583         }
       
  1584         strcpy(r+1, s);
       
  1585         g_free(s);
       
  1586       } else {
       
  1587         *(r+1) = 0;
       
  1588         scr_LogPrint(LPRINT_NORMAL, "Decoding of message sender has failed");
       
  1589         scr_LogPrint(LPRINT_LOG, "Decoding of message sender has failed: %s",
       
  1590                      m);
       
  1591       }
       
  1592     }
       
  1593   }
       
  1594 
  1467 
  1595   if (!from && packet->type != JPACKET_IQ) {
  1468   if (!from && packet->type != JPACKET_IQ) {
  1596     scr_LogPrint(LPRINT_LOGNORM, "Error in packet (could be UTF8-related)");
  1469     scr_LogPrint(LPRINT_LOGNORM, "Error in packet (could be UTF8-related)");
  1597     return;
  1470     return;
  1598   }
  1471   }
  1615         break;
  1488         break;
  1616 
  1489 
  1617     default:
  1490     default:
  1618         scr_LogPrint(LPRINT_LOG, "Unhandled packet type (%d)", packet->type);
  1491         scr_LogPrint(LPRINT_LOG, "Unhandled packet type (%d)", packet->type);
  1619   }
  1492   }
  1620   if (from)
       
  1621     g_free(from);
       
  1622 }
  1493 }
  1623 
  1494 
  1624 /* vim: set expandtab cindent cinoptions=>2\:2(0:  For Vim users... */
  1495 /* vim: set expandtab cindent cinoptions=>2\:2(0:  For Vim users... */