Changeset b1dc403 for protocols


Ignore:
Timestamp:
2015-05-04T21:58:50Z (9 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Children:
5726a0d
Parents:
531eabd (diff), 5ca1416 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Catch up with master.

Location:
protocols
Files:
3 added
3 deleted
27 edited

Legend:

Unmodified
Added
Removed
  • protocols/bee.h

    r531eabd rb1dc403  
    154154G_MODULE_EXPORT void imcb_buddy_times(struct im_connection *ic, const char *handle, time_t login, time_t idle);
    155155/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
    156 G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, char *msg, guint32 flags,
     156G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, guint32 flags,
    157157                                    time_t sent_at);
    158158
  • protocols/bee_user.c

    r531eabd rb1dc403  
    6868        }
    6969
     70        bee->users = g_slist_remove(bee->users, bu);
     71
    7072        g_free(bu->handle);
    7173        g_free(bu->fullname);
     
    7476        g_free(bu->status_msg);
    7577        g_free(bu);
    76 
    77         bee->users = g_slist_remove(bee->users, bu);
    7878
    7979        return 1;
     
    247247}
    248248
    249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at)
     249void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_t flags, time_t sent_at)
    250250{
    251251        bee_t *bee = ic->bee;
  • protocols/jabber/Makefile

    r531eabd rb1dc403  
    1313
    1414# [SH] Program variables
    15 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o
     15objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o hipchat.o
    1616
    1717LFLAGS += -r
  • protocols/jabber/conference.c

    r531eabd rb1dc403  
    359359
    360360        if (subject && chat) {
    361                 s = bud ? strchr(bud->ext_jid, '/') : NULL;
     361                s = (bud && bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
    362362                if (s) {
    363363                        *s = 0;
     
    419419        }
    420420        if (body && body->text_len > 0) {
    421                 s = strchr(bud->ext_jid, '/');
     421                s = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
    422422                if (s) {
    423423                        *s = 0;
  • protocols/jabber/iq.c

    r531eabd rb1dc403  
    2727static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
    2828static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
    29 static int jabber_iq_disco_server(struct im_connection *ic);
    3029
    3130xt_status jabber_pkt_iq(struct xt_node *node, gpointer data)
     
    374373static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
    375374{
     375        struct jabber_data *jd = ic->proto_data;
    376376        struct xt_node *query, *c;
    377377        int initial = (orig != NULL);
     
    388388                char *name = xt_find_attr(c, "name");
    389389                char *sub = xt_find_attr(c, "subscription");
     390                char *mention_name = xt_find_attr(c, "mention_name");
    390391
    391392                if (jid && sub) {
     
    396397                                if (name) {
    397398                                        imcb_rename_buddy(ic, jid, name);
     399                                }
     400
     401                                /* This could also be used to set the full name as nick for fb/gtalk,
     402                                 * but i'm keeping the old (ugly?) default behavior just to be safe */
     403                                if (mention_name && (jd->flags & JFLAG_HIPCHAT)) {
     404                                        imcb_buddy_nick_hint(ic, jid, mention_name);
    398405                                }
    399406                        } else if (strcmp(sub, "remove") == 0) {
     
    855862                                                 struct xt_node *node, struct xt_node *orig);
    856863
    857 static int jabber_iq_disco_server(struct im_connection *ic)
     864int jabber_iq_disco_server(struct im_connection *ic)
    858865{
    859866        struct xt_node *node, *iq;
  • protocols/jabber/jabber.c

    r531eabd rb1dc403  
    6161        s = set_add(&acc->set, "activity_timeout", "600", set_eval_int, acc);
    6262
    63         s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);
    64 
    6563        s = set_add(&acc->set, "display_name", NULL, NULL, acc);
    6664
     
    8381        s = set_add(&acc->set, "server", NULL, set_eval_account, acc);
    8482        s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
     83
     84        if (strcmp(acc->prpl->name, "hipchat") == 0) {
     85                set_setstr(&acc->set, "server", "chat.hipchat.com");
     86        } else {
     87                s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);
     88        }
    8589
    8690        s = set_add(&acc->set, "ssl", "false", set_eval_bool, acc);
     
    121125
    122126        jd->fd = jd->r_inpa = jd->w_inpa = -1;
     127
     128        if (strcmp(acc->prpl->name, "hipchat") == 0) {
     129                jd->flags |= JFLAG_HIPCHAT;
     130        }
    123131
    124132        if (jd->server == NULL) {
     
    656664{
    657665        struct prpl *ret = g_new0(struct prpl, 1);
     666        struct prpl *hipchat = NULL;
    658667
    659668        ret->name = "jabber";
     
    686695
    687696        register_protocol(ret);
    688 }
     697
     698        /* Another one for hipchat, which has completely different logins */
     699        hipchat = g_memdup(ret, sizeof(struct prpl));
     700        hipchat->name = "hipchat";
     701        register_protocol(hipchat);
     702}
  • protocols/jabber/jabber.h

    r531eabd rb1dc403  
    4848
    4949        JFLAG_GTALK =  0x100000,        /* Is Google Talk, as confirmed by iq discovery */
     50        JFLAG_HIPCHAT = 0x200000,       /* Is hipchat, because prpl->name says so */
    5051
    5152        JFLAG_SASL_FB = 0x10000,        /* Trying Facebook authentication. */
     
    235236#define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
    236237
     238/* Hipchat protocol extensions*/
     239#define XMLNS_HIPCHAT         "http://hipchat.com"
     240#define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile"
     241
    237242/* jabber.c */
    238243void jabber_connect(struct im_connection *ic);
     
    249254xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns);
    250255void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data);
     256int jabber_iq_disco_server(struct im_connection *ic);
    251257
    252258/* si.c */
     
    341347void jabber_chat_invite(struct groupchat *c, char *who, char *message);
    342348
     349/* hipchat.c */
     350int jabber_get_hipchat_profile(struct im_connection *ic);
     351xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
     352xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node);
     353
    343354#endif
  • protocols/jabber/jabber_util.c

    r531eabd rb1dc403  
    566566
    567567        if ((s = strchr(jid, '=')) == NULL) {
     568                g_free(jid);
    568569                return NULL;
    569570        }
  • protocols/jabber/s5bytestream.c

    r531eabd rb1dc403  
    2323
    2424#include "jabber.h"
    25 #include "sha1.h"
    2625#include "lib/ftutil.h"
    2726#include <poll.h>
     
    4241
    4342        /* SHA1( SID + Initiator JID + Target JID) */
    44         char *pseudoadr;
     43        char *pseudoaddr;
    4544
    4645        gint connect_timeout;
     
    130129        }
    131130
    132         g_free(bt->pseudoadr);
     131        g_free(bt->pseudoaddr);
    133132
    134133        while (bt->streamhosts) {
     
    254253}
    255254
     255void jabber_bs_remove_events(struct bs_transfer *bt)
     256{
     257        struct jabber_transfer *tf = bt->tf;
     258
     259        if (tf->watch_out) {
     260                b_event_remove(tf->watch_out);
     261                tf->watch_out = 0;
     262        }
     263
     264        if (tf->watch_in) {
     265                b_event_remove(tf->watch_in);
     266                tf->watch_in = 0;
     267        }
     268
     269        if (tf->fd != -1) {
     270                closesocket(tf->fd);
     271                tf->fd = -1;
     272        }
     273
     274        if (bt->connect_timeout) {
     275                b_event_remove(bt->connect_timeout);
     276                bt->connect_timeout = 0;
     277        }
     278}
     279
    256280/* Bad luck */
    257281void jabber_bs_canceled(file_transfer_t *ft, char *reason)
     
    260284
    261285        imcb_log(tf->ic, "File transfer aborted: %s", reason);
     286}
     287
     288static struct jabber_transfer *get_ft_by_sid(GSList *tflist, char *sid) {
     289        GSList *l;
     290        for (l = tflist; l; l = g_slist_next(l)) {
     291                struct jabber_transfer *tft = l->data;
     292                if ((strcmp(tft->sid, sid) == 0)) {
     293                        return tft;
     294                }
     295        }
     296        return NULL;
     297}
     298
     299/* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value
     300 * Returns a newly allocated string */
     301static char *generate_pseudoaddr(char *sid, char *ini_jid, char *tgt_jid) {
     302        char *contents = g_strconcat(sid, ini_jid, tgt_jid, NULL);
     303        char *hash_hex = g_compute_checksum_for_string(G_CHECKSUM_SHA1, contents, -1);
     304        g_free(contents);
     305        return hash_hex;
     306}
     307
     308static jabber_streamhost_t *jabber_streamhost_new(char *jid, char *host, int port)
     309{
     310        jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1);
     311        sh->jid = g_strdup(jid);
     312        sh->host = g_strdup(host);
     313        if (port) {
     314                g_snprintf(sh->port, sizeof(sh->port), "%u", port);
     315        }
     316        return sh;
    262317}
    263318
     
    270325        struct jabber_data *jd = ic->proto_data;
    271326        struct jabber_transfer *tf = NULL;
    272         GSList *tflist;
    273327        struct bs_transfer *bt;
    274328        GSList *shlist = NULL;
    275329        struct xt_node *shnode;
    276 
    277         sha1_state_t sha;
    278         char hash_hex[41];
    279         unsigned char hash[20];
    280         int i;
    281330
    282331        if (!(iq_id   = xt_find_attr(node, "id")) ||
     
    303352                    (port_s = xt_find_attr(shnode, "port")) &&
    304353                    (sscanf(port_s, "%d", &port) == 1)) {
    305                         jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1);
    306                         sh->jid = g_strdup(jid);
    307                         sh->host = g_strdup(host);
    308                         sprintf(sh->port, "%u", port);
    309                         shlist = g_slist_append(shlist, sh);
     354                        shlist = g_slist_append(shlist, jabber_streamhost_new(jid, host, port));
    310355                }
    311356                shnode = shnode->next;
     
    317362        }
    318363
    319         /* Let's see if we can find out what this bytestream should be for... */
    320 
    321         for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
    322                 struct jabber_transfer *tft = tflist->data;
    323                 if ((strcmp(tft->sid, sid) == 0) &&
    324                     (strcmp(tft->ini_jid, ini_jid) == 0) &&
    325                     (strcmp(tft->tgt_jid, tgt_jid) == 0)) {
    326                         tf = tft;
    327                         break;
    328                 }
    329         }
    330 
    331         if (!tf) {
     364        if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) {
    332365                imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);
    333366                return XT_HANDLED;
     
    339372
    340373        tf->ft->canceled = jabber_bs_canceled;
    341 
    342         /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
    343         sha1_init(&sha);
    344         sha1_append(&sha, (unsigned char *) sid, strlen(sid));
    345         sha1_append(&sha, (unsigned char *) ini_jid, strlen(ini_jid));
    346         sha1_append(&sha, (unsigned char *) tgt_jid, strlen(tgt_jid));
    347         sha1_finish(&sha, hash);
    348 
    349         for (i = 0; i < 20; i++) {
    350                 sprintf(hash_hex + i * 2, "%02x", hash[i]);
    351         }
    352374
    353375        bt = g_new0(struct bs_transfer, 1);
     
    356378        bt->sh = shlist->data;
    357379        bt->phase = BS_PHASE_CONNECT;
    358         bt->pseudoadr = g_strdup(hash_hex);
     380        bt->pseudoaddr = generate_pseudoaddr(sid, ini_jid, tgt_jid);
    359381        tf->streamhandle = bt;
    360382        tf->ft->free = jabber_bs_free_transfer;
     
    451473                        .rsv = 0,
    452474                        .atyp = 0x03,
    453                         .addrlen = strlen(bt->pseudoadr),
     475                        .addrlen = strlen(bt->pseudoaddr),
    454476                        .port = 0
    455477                };
     
    468490
    469491                /* copy hash into connect message */
    470                 memcpy(socks5_connect.address, bt->pseudoadr, socks5_connect.addrlen);
     492                memcpy(socks5_connect.address, bt->pseudoaddr, socks5_connect.addrlen);
    471493
    472494                ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect");
     
    558580        if (shlist && shlist->next) {
    559581                bt->sh = shlist->next->data;
     582                jabber_bs_remove_events(bt);
    560583                return jabber_bs_recv_handshake(bt, -1, 0);
    561584        }
     
    731754        struct jabber_data *jd = ic->proto_data;
    732755        struct bs_transfer *bt;
    733         GSList *tflist;
    734756        struct xt_node *c;
    735757        char *sid, *jid;
     
    750772        /* Let's see if we can find out what this bytestream should be for... */
    751773
    752         for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
    753                 struct jabber_transfer *tft = tflist->data;
    754                 if ((strcmp(tft->sid, sid) == 0)) {
    755                         tf = tft;
    756                         break;
    757                 }
    758         }
    759 
    760         if (!tf) {
     774        if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) {
    761775                imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request");
    762776                return XT_HANDLED;
     
    776790                /* using a proxy, abort listen */
    777791
    778                 if (tf->watch_in) {
    779                         b_event_remove(tf->watch_in);
    780                         tf->watch_in = 0;
    781                 }
    782 
    783                 if (tf->fd != -1) {
    784                         closesocket(tf->fd);
    785                         tf->fd = -1;
    786                 }
    787 
    788                 if (bt->connect_timeout) {
    789                         b_event_remove(bt->connect_timeout);
    790                         bt->connect_timeout = 0;
    791                 }
     792                jabber_bs_remove_events(bt);
    792793
    793794                GSList *shlist;
     
    838839{
    839840        char *sid;
    840         GSList *tflist;
    841841        struct jabber_transfer *tf = NULL;
    842842        struct xt_node *query;
     
    846846        sid = xt_find_attr(query, "sid");
    847847
    848         for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
    849                 struct jabber_transfer *tft = tflist->data;
    850                 if ((strcmp(tft->sid, sid) == 0)) {
    851                         tf = tft;
    852                         break;
    853                 }
    854         }
    855 
    856         if (!tf) {
     848        if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) {
    857849                imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream");
    858850                return XT_HANDLED;
     
    883875        *port++ = '\0';
    884876
    885         sh = g_new0(jabber_streamhost_t, 1);
    886         sh->jid = g_strdup(jid);
    887         sh->host = g_strdup(host);
    888         g_snprintf(sh->port, sizeof(sh->port), "%s", port);
     877        sh = jabber_streamhost_new(jid, host, 0);
     878        strncpy(sh->port, port, sizeof(sh->port));
    889879
    890880        return sh;
     
    910900                if (strcmp(proxy, "<local>") == 0) {
    911901                        if ((tf->fd = ft_listen(&tf->saddr, host, port, jd->fd, FALSE, &errmsg)) != -1) {
    912                                 sh = g_new0(jabber_streamhost_t, 1);
    913                                 sh->jid = g_strdup(tf->ini_jid);
    914                                 sh->host = g_strdup(host);
    915                                 g_snprintf(sh->port, sizeof(sh->port), "%s", port);
     902                                sh = jabber_streamhost_new(tf->ini_jid, host, 0);
     903                                strncpy(sh->port, port, sizeof(sh->port));
    916904                                bt->streamhosts = g_slist_append(bt->streamhosts, sh);
    917905
     
    948936{
    949937        struct bs_transfer *bt;
    950         sha1_state_t sha;
    951         char hash_hex[41];
    952         unsigned char hash[20];
    953         int i, ret;
    954 
    955         /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
    956         sha1_init(&sha);
    957         sha1_append(&sha, (unsigned char *) tf->sid, strlen(tf->sid));
    958         sha1_append(&sha, (unsigned char *) tf->ini_jid, strlen(tf->ini_jid));
    959         sha1_append(&sha, (unsigned char *) tf->tgt_jid, strlen(tf->tgt_jid));
    960         sha1_finish(&sha, hash);
    961 
    962         for (i = 0; i < 20; i++) {
    963                 sprintf(hash_hex + i * 2, "%02x", hash[i]);
    964         }
    965938
    966939        bt = g_new0(struct bs_transfer, 1);
    967940        bt->tf = tf;
    968941        bt->phase = BS_PHASE_CONNECT;
    969         bt->pseudoadr = g_strdup(hash_hex);
     942        bt->pseudoaddr = generate_pseudoaddr(tf->sid, tf->ini_jid, tf->tgt_jid);
    970943        tf->streamhandle = bt;
    971944        tf->ft->free = jabber_bs_free_transfer;
     
    974947        jabber_si_set_proxies(bt);
    975948
    976         ret = jabber_bs_send_request(tf, bt->streamhosts);
    977 
    978         return ret;
     949        return jabber_bs_send_request(tf, bt->streamhosts);
    979950}
    980951
     
    11391110                                               socks5_connect.atyp);
    11401111                }
    1141                 if (!(memcmp(socks5_connect.address, bt->pseudoadr, 40) == 0)) {
     1112                if (!(memcmp(socks5_connect.address, bt->pseudoaddr, 40) == 0)) {
    11421113                        return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest");
    11431114                }
  • protocols/jabber/sasl.c

    r531eabd rb1dc403  
    4242        "https://www.facebook.com/dialog/oauth",
    4343        "https://graph.facebook.com/oauth/access_token",
    44         "http://www.bitlbee.org/main.php/Facebook/oauth2.html",
     44        "https://www.bitlbee.org/main.php/Facebook/oauth2.html",
    4545        "offline_access,xmpp_login",
    4646        "126828914005625",
     
    5555        char *s;
    5656        int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0;
    57         int want_oauth = FALSE;
     57        int want_oauth = FALSE, want_hipchat = FALSE;
    5858        GString *mechs;
    5959
     
    7575
    7676        want_oauth = set_getbool(&ic->acc->set, "oauth");
     77        want_hipchat = (jd->flags & JFLAG_HIPCHAT);
    7778
    7879        mechs = g_string_new("");
     
    111112
    112113        reply = xt_new_node("auth", NULL, NULL);
    113         xt_add_attr(reply, "xmlns", XMLNS_SASL);
     114        if (!want_hipchat) {
     115                xt_add_attr(reply, "xmlns", XMLNS_SASL);
     116        } else {
     117                xt_add_attr(reply, "xmlns", XMLNS_HIPCHAT);
     118        }
    114119
    115120        if (sup_gtalk && want_oauth) {
     
    143148        } else if (sup_plain) {
    144149                int len;
    145 
    146                 xt_add_attr(reply, "mechanism", "PLAIN");
     150                GString *gs;
     151                char *username;
     152
     153                if (!want_hipchat) {
     154                        xt_add_attr(reply, "mechanism", "PLAIN");
     155                        username = jd->username;
     156                } else {
     157                        username = jd->me;
     158                }
     159
     160                /* set an arbitrary initial size to avoid reallocations */
     161                gs = g_string_sized_new(128);
    147162
    148163                /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */
    149                 len = strlen(jd->username) + strlen(ic->acc->pass) + 2;
    150                 s = g_malloc(len + 1);
    151                 s[0] = 0;
    152                 strcpy(s + 1, jd->username);
    153                 strcpy(s + 2 + strlen(jd->username), ic->acc->pass);
     164                g_string_append_c(gs, '\0');
     165                g_string_append(gs, username);
     166                g_string_append_c(gs, '\0');
     167                g_string_append(gs, ic->acc->pass);
     168                if (want_hipchat) {
     169                        /* Hipchat's variation adds \0resource at the end */
     170                        g_string_append_c(gs, '\0');
     171                        g_string_append(gs, set_getstr(&ic->acc->set, "resource"));
     172                }
     173
     174                len = gs->len;
     175                s = g_string_free(gs, FALSE);
     176
    154177                reply->text = base64_encode((unsigned char *) s, len);
    155178                reply->text_len = strlen(reply->text);
     
    397420                imcb_log(ic, "Authentication finished");
    398421                jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART;
     422
     423                if (jd->flags & JFLAG_HIPCHAT) {
     424                        return hipchat_handle_success(ic, node);
     425                }
    399426        } else if (strcmp(node->name, "failure") == 0) {
    400427                imcb_error(ic, "Authentication failure");
  • protocols/msn/Makefile

    r531eabd rb1dc403  
    1313
    1414# [SH] Program variables
    15 objects = msn.o msn_util.o ns.o sb.o soap.o tables.o
     15objects = msn.o msn_util.o ns.o soap.o tables.o gw.o
    1616
    1717LFLAGS += -r
  • protocols/msn/msn.c

    r531eabd rb1dc403  
    3030int msn_chat_id;
    3131GSList *msn_connections;
    32 GSList *msn_switchboards;
    3332
    3433static char *set_eval_display_name(set_t *set, char *value);
     
    4140        s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
    4241
    43         s = set_add(&acc->set, "server", MSN_NS_HOST, set_eval_account, acc);
     42        s = set_add(&acc->set, "server", NULL, set_eval_account, acc);
    4443        s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
    4544
     
    4847
    4948        set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
    50         set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);
    5149
    5250        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
     
    5856        struct im_connection *ic = imcb_new(acc);
    5957        struct msn_data *md = g_new0(struct msn_data, 1);
     58        char *server = set_getstr(&ic->acc->set, "server");
    6059
    6160        ic->proto_data = md;
    6261        ic->flags |= OPT_PONGS | OPT_PONGED;
     62
     63        if (!server) {
     64                server = "geo.gateway.messenger.live.com";
     65        }
    6366
    6467        if (strchr(acc->user, '@') == NULL) {
     
    7174        md->away_state = msn_away_state_list;
    7275        md->domaintree = g_tree_new(msn_domaintree_cmp);
    73         md->ns->fd = -1;
     76        md->fd = -1;
     77        md->is_http = TRUE;
    7478
    7579        msn_connections = g_slist_prepend(msn_connections, ic);
    7680
    7781        imcb_log(ic, "Connecting");
    78         msn_ns_connect(ic, md->ns,
    79                        set_getstr(&ic->acc->set, "server"),
     82        msn_ns_connect(ic, server,
    8083                       set_getint(&ic->acc->set, "port"));
    8184}
     
    8891
    8992        if (md) {
    90                 /** Disabling MSN ft support for now.
    91                 while( md->filetransfers ) {
    92                         imcb_file_canceled( md->filetransfers->data, "Closing connection" );
    93                 }
    94                 */
    95 
    96                 msn_ns_close(md->ns);
    97 
    98                 while (md->switchboards) {
    99                         msn_sb_destroy(md->switchboards->data);
    100                 }
    101 
    102                 msn_msgq_purge(ic, &md->msgq);
     93                msn_ns_close(md);
     94
    10395                msn_soapq_flush(ic, FALSE);
    10496
     
    112104                while (md->groups) {
    113105                        struct msn_group *mg = md->groups->data;
     106                        md->groups = g_slist_remove(md->groups, mg);
    114107                        g_free(mg->id);
    115108                        g_free(mg->name);
    116109                        g_free(mg);
    117                         md->groups = g_slist_remove(md->groups, mg);
    118110                }
    119111
     
    127119                while (md->grpq) {
    128120                        struct msn_groupadd *ga = md->grpq->data;
     121                        md->grpq = g_slist_remove(md->grpq, ga);
    129122                        g_free(ga->group);
    130123                        g_free(ga->who);
    131124                        g_free(ga);
    132                         md->grpq = g_slist_remove(md->grpq, ga);
    133125                }
    134126
     
    152144{
    153145        struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who);
    154         struct msn_buddy_data *bd = bu ? bu->data : NULL;
    155         struct msn_switchboard *sb;
    156146
    157147#ifdef DEBUG
    158148        if (strcmp(who, "raw") == 0) {
    159149                msn_ns_write(ic, -1, "%s\r\n", message);
    160         } else
     150                return 0;
     151        }
    161152#endif
    162         if (bd && bd->flags & MSN_BUDDY_FED) {
    163                 msn_ns_sendmessage(ic, bu, message);
    164         } else if ((sb = msn_sb_by_handle(ic, who))) {
    165                 return(msn_sb_sendmessage(sb, message));
    166         } else {
    167                 struct msn_message *m;
    168 
    169                 /* Create a message. We have to arrange a usable switchboard, and send the message later. */
    170                 m = g_new0(struct msn_message, 1);
    171                 m->who = g_strdup(who);
    172                 m->text = g_strdup(message);
    173 
    174                 return msn_sb_write_msg(ic, m);
    175         }
    176 
     153
     154        msn_ns_sendmessage(ic, bu, message);
    177155        return(0);
    178156}
     
    196174static void msn_set_away(struct im_connection *ic, char *state, char *message)
    197175{
    198         char *uux;
    199176        struct msn_data *md = ic->proto_data;
     177        char *nick, *psm, *idle, *statecode, *body, *buf;
    200178
    201179        if (state == NULL) {
     
    205183        }
    206184
    207         if (!msn_ns_write(ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2)) {
    208                 return;
    209         }
    210 
    211         uux = g_markup_printf_escaped("<EndpointData><Capabilities>%d:%02d"
    212                                       "</Capabilities></EndpointData>",
    213                                       MSN_CAP1, MSN_CAP2);
    214         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    215         g_free(uux);
    216 
    217         uux = g_markup_printf_escaped("<PrivateEndpointData><EpName>%s</EpName>"
    218                                       "<Idle>%s</Idle><ClientType>%d</ClientType>"
    219                                       "<State>%s</State></PrivateEndpointData>",
    220                                       md->uuid,
    221                                       strcmp(md->away_state->code, "IDL") ? "false" : "true",
    222                                       1,  /* ? */
    223                                       md->away_state->code);
    224         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    225         g_free(uux);
    226 
    227         uux = g_markup_printf_escaped("<Data><DDP></DDP><PSM>%s</PSM>"
    228                                       "<CurrentMedia></CurrentMedia>"
    229                                       "<MachineGuid>%s</MachineGuid></Data>",
    230                                       message ? message : "", md->uuid);
    231         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    232         g_free(uux);
     185        statecode = (char *) md->away_state->code;
     186        nick = set_getstr(&ic->acc->set, "display_name");
     187        psm = message ? message : "";
     188        idle = (strcmp(statecode, "IDL") == 0) ? "false" : "true";
     189
     190        body = g_markup_printf_escaped(MSN_PUT_USER_BODY,
     191                nick, psm, psm, md->uuid, statecode, md->uuid, idle, statecode,
     192                MSN_CAP1, MSN_CAP2, MSN_CAP1, MSN_CAP2
     193        );
     194
     195        buf = g_strdup_printf(MSN_PUT_HEADERS, ic->acc->user, ic->acc->user, md->uuid,
     196                "/user", "application/user+xml",
     197                strlen(body), body);
     198        msn_ns_write(ic, -1, "PUT %d %zd\r\n%s", ++md->trId, strlen(buf), buf);
     199
     200        g_free(buf);
     201        g_free(body);
    233202}
    234203
     
    256225static void msn_chat_msg(struct groupchat *c, char *message, int flags)
    257226{
    258         struct msn_switchboard *sb = msn_sb_by_chat(c);
    259 
    260         if (sb) {
    261                 msn_sb_sendmessage(sb, message);
    262         }
    263         /* FIXME: Error handling (although this can't happen unless something's
    264            already severely broken) disappeared here! */
     227        /* TODO: groupchats*/
    265228}
    266229
    267230static void msn_chat_invite(struct groupchat *c, char *who, char *message)
    268231{
    269         struct msn_switchboard *sb = msn_sb_by_chat(c);
    270 
    271         if (sb) {
    272                 msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, who);
    273         }
     232        /* TODO: groupchats*/
    274233}
    275234
    276235static void msn_chat_leave(struct groupchat *c)
    277236{
    278         struct msn_switchboard *sb = msn_sb_by_chat(c);
    279 
    280         if (sb) {
    281                 msn_sb_write(sb, "OUT\r\n");
    282         }
     237        /* TODO: groupchats*/
    283238}
    284239
    285240static struct groupchat *msn_chat_with(struct im_connection *ic, char *who)
    286241{
    287         struct msn_switchboard *sb;
     242        /* TODO: groupchats*/
    288243        struct groupchat *c = imcb_chat_new(ic, who);
    289 
    290         if ((sb = msn_sb_by_handle(ic, who))) {
    291                 debug("Converting existing switchboard to %s to a groupchat", who);
    292                 return msn_sb_to_chat(sb);
    293         } else {
    294                 struct msn_message *m;
    295 
    296                 /* Create a magic message. This is quite hackish, but who cares? :-P */
    297                 m = g_new0(struct msn_message, 1);
    298                 m->who = g_strdup(who);
    299                 m->text = g_strdup(GROUPCHAT_SWITCHBOARD_MESSAGE);
    300 
    301                 msn_sb_write_msg(ic, m);
    302 
    303                 return c;
    304         }
     244        return c;
    305245}
    306246
     
    322262static void msn_add_deny(struct im_connection *ic, char *who)
    323263{
    324         struct msn_switchboard *sb;
    325 
    326264        msn_buddy_list_add(ic, MSN_BUDDY_BL, who, who, NULL);
    327 
    328         /* If there's still a conversation with this person, close it. */
    329         if ((sb = msn_sb_by_handle(ic, who))) {
    330                 msn_sb_destroy(sb);
    331         }
    332265}
    333266
     
    462395        ret->buddy_action = msn_buddy_action;
    463396
    464         //ret->transfer_request = msn_ftp_transfer_request;
    465 
    466397        register_protocol(ret);
    467398}
  • protocols/msn/msn.h

    r531eabd rb1dc403  
    3232#define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r"
    3333#define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r"
    34 #define SB_KEEPALIVE_MESSAGE "\r\r\rDONT HANG UP ON ME!\r\r\r"
    3534
    3635#ifdef DEBUG_MSN
     
    6059#define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM"
    6160#define MSNP11_PROD_ID  "PROD0120PW!CCV9@"
    62 #define MSNP_VER        "MSNP18"
     61#define MSNP_VER        "MSNP21"
    6362#define MSNP_BUILD      "14.0.8117.416"
    6463
     
    6867#define MSN_CAP2        0x0000
    6968
    70 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \
     69#define MSN_BASE_HEADERS \
     70        "Routing: 1.0\r\n" \
     71        "To: 1:%s\r\n" \
     72        "From: 1:%s;epid={%s}\r\n" \
     73        "\r\n" \
     74        "Reliability: 1.0\r\n" \
     75        "\r\n"
     76
     77#define MSN_MESSAGE_HEADERS MSN_BASE_HEADERS \
     78        "Messaging: 2.0\r\n" \
     79        "Message-Type: Text\r\n" \
     80        "Content-Length: %zd\r\n" \
    7181        "Content-Type: text/plain; charset=UTF-8\r\n" \
    72         "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \
    73         "X-MMS-IM-Format: FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n" \
    74         "\r\n"
     82        "X-MMS-IM-Format: FN=Segoe%%20UI; EF=; CO=0; CS=0; PF=0\r\n" \
     83        "\r\n" \
     84        "%s"
     85
     86#define MSN_PUT_HEADERS MSN_BASE_HEADERS \
     87        "Publication: 1.0\r\n" \
     88        "Uri: %s\r\n" \
     89        "Content-Type: %s\r\n" \
     90        "Content-Length: %zd\r\n" \
     91        "\r\n" \
     92        "%s"
     93
     94#define MSN_PUT_USER_BODY \
     95        "<user>" \
     96        "<s n=\"PE\"><UserTileLocation></UserTileLocation><FriendlyName>%s</FriendlyName><PSM>%s</PSM><DDP></DDP>" \
     97        "<Scene></Scene><ASN></ASN><ColorScheme>-3</ColorScheme><BDG></BDG><RUM>%s</RUM><RUL></RUL><RLT>0</RLT>" \
     98        "<RID></RID><SUL></SUL><MachineGuid>%s</MachineGuid></s>" \
     99        "<s n=\"IM\"><Status>%s</Status><CurrentMedia></CurrentMedia></s>" \
     100        "<sep n=\"PD\"><ClientType>1</ClientType><EpName>%s</EpName><Idle>%s</Idle><State>%s</State></sep>" \
     101        "<sep n=\"PE\"><VER>BitlBee:" BITLBEE_VERSION "</VER><TYP>1</TYP><Capabilities>%d:%d</Capabilities></sep>" \
     102        "<sep n=\"IM\"><Capabilities>%d:%d</Capabilities></sep>" \
     103        "</user>"
    75104
    76105#define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \
     
    84113        "ID: 1\r\n" \
    85114        "\r\n"
    86 
    87 #define MSN_SB_KEEPALIVE_HEADERS "MIME-Version: 1.0\r\n" \
    88         "Content-Type: text/x-ping\r\n" \
    89         "\r\n\r\n"
    90115
    91116#define PROFILE_URL "http://members.msn.com/"
     
    99124} msn_flags_t;
    100125
    101 struct msn_handler_data {
     126struct msn_gw {
     127        char *last_host;
     128        int port;
     129        gboolean ssl;
     130
     131        char *session_id;
     132
     133        GByteArray *in;
     134        GByteArray *out;
     135
     136        int poll_timeout;
     137
     138        b_event_handler callback;
     139
     140        struct im_connection *ic;
     141        struct msn_data *md;
     142
     143        gboolean open;
     144        gboolean waiting;
     145        gboolean polling;
     146};
     147
     148struct msn_data {
    102149        int fd, inpa;
    103150        int rxlen;
     
    107154        char *cmd_text;
    108155
    109         /* Either ic or sb */
    110         gpointer data;
    111 
    112         int (*exec_command) (struct msn_handler_data *handler, char **cmd, int count);
    113         int (*exec_message) (struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count);
    114 };
    115 
    116 struct msn_data {
    117156        struct im_connection *ic;
    118157
    119         struct msn_handler_data ns[1];
    120158        msn_flags_t flags;
    121159
     
    126164
    127165        GSList *msgq, *grpq, *soapq;
    128         GSList *switchboards;
    129         int sb_failures;
    130         time_t first_sb_failure;
    131166
    132167        const struct msn_away_state *away_state;
     
    139174        GTree *domaintree;
    140175        int adl_todo;
    141 };
    142 
    143 struct msn_switchboard {
    144         struct im_connection *ic;
    145 
    146         /* The following two are also in the handler. TODO: Clean up. */
    147         int fd;
    148         gint inp;
    149         struct msn_handler_data *handler;
    150         gint keepalive;
    151 
    152         int trId;
    153         int ready;
    154 
    155         int session;
    156         char *key;
    157 
    158         GSList *msgq;
    159         char *who;
    160         struct groupchat *chat;
     176
     177        gboolean is_http;
     178        struct msn_gw *gw;
    161179};
    162180
     
    205223#define STATUS_FATAL            1
    206224#define STATUS_SB_FATAL         2
    207 #define STATUS_SB_IM_SPARE      4       /* Make one-to-one conversation switchboard available again, invite failed. */
    208 #define STATUS_SB_CHAT_SPARE    8       /* Same, but also for groupchats (not used yet). */
    209225
    210226extern int msn_chat_id;
     
    218234   before doing *anything* else. */
    219235extern GSList *msn_connections;
    220 extern GSList *msn_switchboards;
    221236
    222237/* ns.c */
    223238int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4);
    224 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port);
    225 void msn_ns_close(struct msn_handler_data *handler);
     239gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port);
     240void msn_ns_close(struct msn_data *handler);
    226241void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error);
    227242void msn_auth_got_contact_list(struct im_connection *ic);
    228243int msn_ns_finish_login(struct im_connection *ic);
    229244int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text);
    230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq);
     245int msn_ns_command(struct msn_data *md, char **cmd, int num_parts);
     246int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts);
    231247
    232248/* msn_util.c */
     
    235251int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group);
    236252void msn_buddy_ask(bee_user_t *bu);
    237 char **msn_linesplit(char *line);
    238 int msn_handler(struct msn_handler_data *h);
    239 void msn_msgq_purge(struct im_connection *ic, GSList **list);
     253void msn_queue_feed(struct msn_data *h, char *bytes, int st);
     254int msn_handler(struct msn_data *h);
    240255char *msn_p11_challenge(char *challenge);
    241256gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_);
     
    251266const struct msn_status_code *msn_status_by_number(int number);
    252267
    253 /* sb.c */
    254 int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);;
    255 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session);
    256 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle);
    257 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c);
    258 struct msn_switchboard *msn_sb_spare(struct im_connection *ic);
    259 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text);
    260 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb);
    261 void msn_sb_destroy(struct msn_switchboard *sb);
    262 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond);
    263 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m);
    264 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial);
    265 void msn_sb_stop_keepalives(struct msn_switchboard *sb);
     268/* gw.c */
     269struct msn_gw *msn_gw_new(struct im_connection *ic);
     270void msn_gw_free(struct msn_gw *gw);
     271void msn_gw_open(struct msn_gw *gw);
     272ssize_t msn_gw_read(struct msn_gw *gw, char **buf);
     273void msn_gw_write(struct msn_gw *gw, char *buf, size_t len);
    266274
    267275#endif //_MSN_H
  • protocols/msn/msn_util.c

    r531eabd rb1dc403  
    5555
    5656        *groupid = '\0';
    57 #if 0
    58         if (group) {
    59                 int i;
    60                 for (i = 0; i < md->groupcount; i++) {
    61                         if (g_strcasecmp(md->grouplist[i], group) == 0) {
    62                                 g_snprintf(groupid, sizeof(groupid), " %d", i);
    63                                 break;
    64                         }
    65                 }
    66 
    67                 if (*groupid == '\0') {
    68                         /* Have to create this group, it doesn't exist yet. */
    69                         struct msn_groupadd *ga;
    70                         GSList *l;
    71 
    72                         for (l = md->grpq; l; l = l->next) {
    73                                 ga = l->data;
    74                                 if (g_strcasecmp(ga->group, group) == 0) {
    75                                         break;
    76                                 }
    77                         }
    78 
    79                         ga = g_new0(struct msn_groupadd, 1);
    80                         ga->who = g_strdup(who);
    81                         ga->group = g_strdup(group);
    82                         md->grpq = g_slist_prepend(md->grpq, ga);
    83 
    84                         if (l == NULL) {
    85                                 char groupname[strlen(group) + 1];
    86                                 strcpy(groupname, group);
    87                                 http_encode(groupname);
    88                                 g_snprintf(buf, sizeof(buf), "ADG %d %s %d\r\n", ++md->trId, groupname, 0);
    89                                 return msn_write(ic, buf, strlen(buf));
    90                         } else {
    91                                 /* This can happen if the user's doing lots of adds to a
    92                                    new group at once; we're still waiting for the server
    93                                    to confirm group creation. */
    94                                 return 1;
    95                         }
    96                 }
    97         }
    98 #endif
    9957
    10058        if (!((bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    13290
    13391        *groupid = '\0';
    134 #if 0
    135         if (group) {
    136                 int i;
    137                 for (i = 0; i < md->groupcount; i++) {
    138                         if (g_strcasecmp(md->grouplist[i], group) == 0) {
    139                                 g_snprintf(groupid, sizeof(groupid), " %d", i);
    140                                 break;
    141                         }
    142                 }
    143         }
    144 #endif
    14592
    14693        if (!(bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    174121};
    175122
    176 static void msn_buddy_ask_yes(void *data)
     123static void msn_buddy_ask_free(void *data)
    177124{
    178125        struct msn_buddy_ask_data *bla = data;
    179 
    180         msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL);
    181 
    182         imcb_ask_add(bla->ic, bla->handle, NULL);
    183126
    184127        g_free(bla->handle);
     
    187130}
    188131
     132static void msn_buddy_ask_yes(void *data)
     133{
     134        struct msn_buddy_ask_data *bla = data;
     135
     136        msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL);
     137
     138        imcb_ask_add(bla->ic, bla->handle, NULL);
     139
     140        msn_buddy_ask_free(bla);
     141}
     142
    189143static void msn_buddy_ask_no(void *data)
    190144{
     
    193147        msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL);
    194148
    195         g_free(bla->handle);
    196         g_free(bla->realname);
    197         g_free(bla);
     149        msn_buddy_ask_free(bla);
    198150}
    199151
     
    216168                   "The user %s (%s) wants to add you to his/her buddy list.",
    217169                   bu->handle, bu->fullname);
    218         imcb_ask(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no);
    219 }
    220 
    221 /* *NOT* thread-safe, but that's not a problem for now... */
    222 char **msn_linesplit(char *line)
    223 {
    224         static char **ret = NULL;
    225         static int size = 3;
    226         int i, n = 0;
    227 
    228         if (ret == NULL) {
    229                 ret = g_new0(char*, size);
    230         }
    231 
    232         for (i = 0; line[i] && line[i] == ' '; i++) {
    233                 ;
    234         }
    235         if (line[i]) {
    236                 ret[n++] = line + i;
    237                 for (i++; line[i]; i++) {
    238                         if (line[i] == ' ') {
    239                                 line[i] = 0;
    240                         } else if (line[i] != ' ' && !line[i - 1]) {
    241                                 ret[n++] = line + i;
    242                         }
    243 
    244                         if (n >= size) {
    245                                 ret = g_renew(char*, ret, size += 2);
    246                         }
    247                 }
    248         }
    249         ret[n] = NULL;
    250 
    251         return(ret);
     170
     171        imcb_ask_with_free(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no, msn_buddy_ask_free);
     172}
     173
     174void msn_queue_feed(struct msn_data *h, char *bytes, int st)
     175{
     176        h->rxq = g_renew(char, h->rxq, h->rxlen + st);
     177        memcpy(h->rxq + h->rxlen, bytes, st);
     178        h->rxlen += st;
     179
     180        if (getenv("BITLBEE_DEBUG")) {
     181                fprintf(stderr, "\n\x1b[92m<<< ");
     182                write(2, bytes , st);
     183                fprintf(stderr, "\x1b[97m");
     184        }
    252185}
    253186
     
    260193                   1: OK */
    261194
    262 int msn_handler(struct msn_handler_data *h)
    263 {
    264         int st;
    265 
    266         h->rxq = g_renew(char, h->rxq, h->rxlen + 1024);
    267         st = read(h->fd, h->rxq + h->rxlen, 1024);
    268         h->rxlen += st;
    269 
    270         if (st <= 0) {
    271                 return(-1);
    272         }
    273 
    274         if (getenv("BITLBEE_DEBUG")) {
    275                 write(2, "->C:", 4);
    276                 write(2, h->rxq + h->rxlen - st, st);
    277         }
     195int msn_handler(struct msn_data *h)
     196{
     197        int st = 1;
    278198
    279199        while (st) {
     
    287207
    288208                                        cmd_text = g_strndup(h->rxq, i);
    289                                         cmd = msn_linesplit(cmd_text);
    290                                         for (count = 0; cmd[count]; count++) {
    291                                                 ;
    292                                         }
    293                                         st = h->exec_command(h, cmd, count);
     209                                        cmd = g_strsplit_set(cmd_text, " ", -1);
     210                                        count = g_strv_length(cmd);
     211
     212                                        st = msn_ns_command(h, cmd, count);
     213
     214                                        g_strfreev(cmd);
    294215                                        g_free(cmd_text);
    295216
     
    314235                        /* If we reached the end of the buffer, there's still an incomplete command there.
    315236                           Return and wait for more data. */
    316                         if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
     237                        if (i && i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
    317238                                break;
    318239                        }
     
    327248
    328249                        msg = g_strndup(h->rxq, h->msglen);
    329                         cmd = msn_linesplit(h->cmd_text);
    330                         for (count = 0; cmd[count]; count++) {
    331                                 ;
    332                         }
    333 
    334                         st = h->exec_message(h, msg, h->msglen, cmd, count);
     250
     251                        cmd = g_strsplit_set(h->cmd_text, " ", -1);
     252                        count = g_strv_length(cmd);
     253
     254                        st = msn_ns_message(h, msg, h->msglen, cmd, count);
     255
     256                        g_strfreev(cmd);
    335257                        g_free(msg);
    336258                        g_free(h->cmd_text);
     
    366288}
    367289
    368 void msn_msgq_purge(struct im_connection *ic, GSList **list)
    369 {
    370         struct msn_message *m;
    371         GString *ret;
    372         GSList *l;
    373         int n = 0;
    374 
    375         l = *list;
    376         if (l == NULL) {
    377                 return;
    378         }
    379 
    380         m = l->data;
    381         ret = g_string_sized_new(1024);
    382         g_string_printf(ret, "Warning: Cleaning up MSN (switchboard) connection with unsent "
    383                         "messages to %s:", m->who ? m->who : "unknown recipient");
    384 
    385         while (l) {
    386                 m = l->data;
    387 
    388                 if (strncmp(m->text, "\r\r\r", 3) != 0) {
    389                         g_string_append_printf(ret, "\n%s", m->text);
    390                         n++;
    391                 }
    392 
    393                 g_free(m->who);
    394                 g_free(m->text);
    395                 g_free(m);
    396 
    397                 l = l->next;
    398         }
    399         g_slist_free(*list);
    400         *list = NULL;
    401 
    402         if (n > 0) {
    403                 imcb_log(ic, "%s", ret->str);
    404         }
    405         g_string_free(ret, TRUE);
    406 }
    407 
    408290/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
    409291char *msn_p11_challenge(char *challenge)
     
    529411int msn_ns_set_display_name(struct im_connection *ic, const char *value)
    530412{
    531         struct msn_data *md = ic->proto_data;
    532         char fn[strlen(value) * 3 + 1];
    533 
    534         strcpy(fn, value);
    535         http_encode(fn);
    536 
    537         /* Note: We don't actually know if the server accepted the new name,
    538            and won't give proper feedback yet if it doesn't. */
    539         return msn_ns_write(ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn);
     413        // TODO, implement this through msn_set_away's method
     414        return 1;
    540415}
    541416
  • protocols/msn/ns.c

    r531eabd rb1dc403  
    3535static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond);
    3636static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond);
    37 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);
    38 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);
    3937
    4038static void msn_ns_send_adl_start(struct im_connection *ic);
    4139static void msn_ns_send_adl(struct im_connection *ic);
     40static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd);
     41static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action);
     42static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put);
    4243
    4344int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...)
     
    5455
    5556        if (fd < 0) {
    56                 fd = md->ns->fd;
     57                fd = md->fd;
    5758        }
    5859
    5960        if (getenv("BITLBEE_DEBUG")) {
    60                 fprintf(stderr, "->NS%d:%s\n", fd, out);
     61                fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out);
    6162        }
    6263
    6364        len = strlen(out);
    64         st = write(fd, out, len);
     65
     66        if (md->is_http) {
     67                st = len;
     68                msn_gw_write(md->gw, out, len);
     69        } else {
     70                st = write(fd, out, len);
     71        }
     72
    6573        g_free(out);
    6674        if (st != len) {
     
    7381}
    7482
    75 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port)
    76 {
    77         if (handler->fd >= 0) {
    78                 closesocket(handler->fd);
    79         }
    80 
    81         handler->exec_command = msn_ns_command;
    82         handler->exec_message = msn_ns_message;
    83         handler->data = ic;
    84         handler->fd = proxy_connect(host, port, msn_ns_connected, handler);
    85         if (handler->fd < 0) {
     83gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port)
     84{
     85        struct msn_data *md = ic->proto_data;
     86
     87        if (md->fd >= 0) {
     88                closesocket(md->fd);
     89        }
     90
     91        if (md->is_http) {
     92                md->gw = msn_gw_new(ic);
     93                md->gw->callback = msn_ns_callback;
     94                msn_ns_connected(md, -1, B_EV_IO_READ);
     95        } else {
     96                md->fd = proxy_connect(host, port, msn_ns_connected, md);
     97                if (md->fd < 0) {
     98                        imcb_error(ic, "Could not connect to server");
     99                        imc_logout(ic, TRUE);
     100                        return FALSE;
     101                }
     102        }
     103
     104        return TRUE;
     105}
     106
     107static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond)
     108{
     109        struct msn_data *md = data;
     110        struct im_connection *ic = md->ic;
     111
     112        if (source == -1 && !md->is_http) {
    86113                imcb_error(ic, "Could not connect to server");
    87114                imc_logout(ic, TRUE);
     
    89116        }
    90117
    91         return TRUE;
    92 }
    93 
    94 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond)
    95 {
    96         struct msn_handler_data *handler = data;
    97         struct im_connection *ic = handler->data;
    98         struct msn_data *md;
    99 
    100         if (!g_slist_find(msn_connections, ic)) {
    101                 return FALSE;
    102         }
    103 
    104         md = ic->proto_data;
    105 
    106         if (source == -1) {
    107                 imcb_error(ic, "Could not connect to server");
    108                 imc_logout(ic, TRUE);
    109                 return FALSE;
    110         }
    111 
    112         g_free(handler->rxq);
    113         handler->rxlen = 0;
    114         handler->rxq = g_new0(char, 1);
     118        g_free(md->rxq);
     119        md->rxlen = 0;
     120        md->rxq = g_new0(char, 1);
    115121
    116122        if (md->uuid == NULL) {
     
    130136
    131137        if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) {
    132                 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler);
     138                if (!md->is_http) {
     139                        md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md);
     140                }
    133141                imcb_log(ic, "Connected to server, waiting for reply");
    134142        }
     
    137145}
    138146
    139 void msn_ns_close(struct msn_handler_data *handler)
    140 {
    141         if (handler->fd >= 0) {
    142                 closesocket(handler->fd);
    143                 b_event_remove(handler->inpa);
    144         }
    145 
    146         handler->fd = handler->inpa = -1;
    147         g_free(handler->rxq);
    148         g_free(handler->cmd_text);
    149 
    150         handler->rxlen = 0;
    151         handler->rxq = NULL;
    152         handler->cmd_text = NULL;
     147void msn_ns_close(struct msn_data *md)
     148{
     149        if (md->gw) {
     150                msn_gw_free(md->gw);
     151        }
     152        if (md->fd >= 0) {
     153                closesocket(md->fd);
     154                b_event_remove(md->inpa);
     155        }
     156
     157        md->fd = md->inpa = -1;
     158        g_free(md->rxq);
     159        g_free(md->cmd_text);
     160
     161        md->rxlen = 0;
     162        md->rxq = NULL;
     163        md->cmd_text = NULL;
    153164}
    154165
    155166static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond)
    156167{
    157         struct msn_handler_data *handler = data;
    158         struct im_connection *ic = handler->data;
    159 
    160         if (msn_handler(handler) == -1) {  /* Don't do this on ret == 0, it's already done then. */
     168        struct msn_data *md = data;
     169        struct im_connection *ic = md->ic;
     170        char *bytes;
     171        int st;
     172
     173        if (md->is_http) {
     174                st = msn_gw_read(md->gw, &bytes);
     175        } else {
     176                bytes = g_malloc(1024);
     177                st = read(md->fd, bytes, 1024);
     178        }
     179
     180        if (st <= 0) {
    161181                imcb_error(ic, "Error while reading from server");
    162182                imc_logout(ic, TRUE);
    163 
    164183                return FALSE;
    165         } else {
    166                 return TRUE;
    167         }
    168 }
    169 
    170 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts)
    171 {
    172         struct im_connection *ic = handler->data;
    173         struct msn_data *md = ic->proto_data;
     184        }
     185
     186        msn_queue_feed(md, bytes, st);
     187
     188        g_free(bytes);
     189
     190        /* Ignore ret == 0, it's already disconnected then. */
     191        msn_handler(md);
     192
     193        return TRUE;
     194       
     195}
     196
     197int msn_ns_command(struct msn_data *md, char **cmd, int num_parts)
     198{
     199        struct im_connection *ic = md->ic;
    174200
    175201        if (num_parts == 0) {
     
    185211                }
    186212
    187                 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
     213                return(msn_ns_write(ic, md->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINClhmclNlbnRVVENUaW1lOiA2MzU2MTQ3OTU5NzgzOTAwMDANCklzR2VvWGZyOiB0cnVlDQo=\r\n",
    188214                                    ++md->trId, ic->acc->user));
    189215        } else if (strcmp(cmd[0], "CVR") == 0) {
    190216                /* We don't give a damn about the information we just received */
    191                 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
     217                return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
    192218        } else if (strcmp(cmd[0], "XFR") == 0) {
    193219                char *server;
     
    195221
    196222                if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) {
    197                         b_event_remove(handler->inpa);
    198                         handler->inpa = -1;
     223                        b_event_remove(md->inpa);
     224                        md->inpa = -1;
    199225
    200226                        server = strchr(cmd[3], ':');
     
    209235
    210236                        imcb_log(ic, "Transferring to other server");
    211                         return msn_ns_connect(ic, handler, server, port);
    212                 } else if (num_parts >= 6 && strcmp(cmd[2], "SB") == 0) {
    213                         struct msn_switchboard *sb;
    214 
    215                         server = strchr(cmd[3], ':');
    216                         if (!server) {
    217                                 imcb_error(ic, "Syntax error");
    218                                 imc_logout(ic, TRUE);
    219                                 return(0);
    220                         }
    221                         *server = 0;
    222                         port = atoi(server + 1);
    223                         server = cmd[3];
    224 
    225                         if (strcmp(cmd[4], "CKI") != 0) {
    226                                 imcb_error(ic, "Unknown authentication method for switchboard");
    227                                 imc_logout(ic, TRUE);
    228                                 return(0);
    229                         }
    230 
    231                         debug("Connecting to a new switchboard with key %s", cmd[5]);
    232 
    233                         if ((sb = msn_sb_create(ic, server, port, cmd[5], MSN_SB_NEW)) == NULL) {
    234                                 /* Although this isn't strictly fatal for the NS connection, it's
    235                                    definitely something serious (we ran out of file descriptors?). */
    236                                 imcb_error(ic, "Could not create new switchboard");
    237                                 imc_logout(ic, TRUE);
    238                                 return(0);
    239                         }
    240 
    241                         if (md->msgq) {
    242                                 struct msn_message *m = md->msgq->data;
    243                                 GSList *l;
    244 
    245                                 sb->who = g_strdup(m->who);
    246 
    247                                 /* Move all the messages to the first user in the message
    248                                    queue to the switchboard message queue. */
    249                                 l = md->msgq;
    250                                 while (l) {
    251                                         m = l->data;
    252                                         l = l->next;
    253                                         if (strcmp(m->who, sb->who) == 0) {
    254                                                 sb->msgq = g_slist_append(sb->msgq, m);
    255                                                 md->msgq = g_slist_remove(md->msgq, m);
    256                                         }
    257                                 }
    258                         }
     237                        return msn_ns_connect(ic, server, port);
    259238                } else {
    260239                        imcb_error(ic, "Syntax error");
     
    290269                }
    291270
    292                 handler->msglen = atoi(cmd[3]);
    293 
    294                 if (handler->msglen <= 0) {
     271                md->msglen = atoi(cmd[3]);
     272
     273                if (md->msglen <= 0) {
    295274                        imcb_error(ic, "Syntax error");
    296275                        imc_logout(ic, TRUE);
    297276                        return(0);
    298277                }
    299         } else if (strcmp(cmd[0], "BLP") == 0) {
    300                 msn_ns_send_adl_start(ic);
    301                 return msn_ns_finish_login(ic);
    302278        } else if (strcmp(cmd[0], "ADL") == 0) {
    303279                if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) {
     
    305281                        return msn_ns_finish_login(ic);
    306282                } else if (num_parts >= 3) {
    307                         handler->msglen = atoi(cmd[2]);
    308                 }
    309         } else if (strcmp(cmd[0], "PRP") == 0) {
    310                 imcb_connected(ic);
     283                        md->msglen = atoi(cmd[2]);
     284                }
    311285        } else if (strcmp(cmd[0], "CHL") == 0) {
    312286                char *resp;
     
    326300                g_free(resp);
    327301                return st;
    328         } else if (strcmp(cmd[0], "ILN") == 0 || strcmp(cmd[0], "NLN") == 0) {
    329                 const struct msn_away_state *st;
    330                 const char *handle;
    331                 int cap = 0;
    332 
    333                 if (num_parts < 6) {
    334                         imcb_error(ic, "Syntax error");
    335                         imc_logout(ic, TRUE);
    336                         return(0);
    337                 }
    338                 /* ILN and NLN are more or less the same, except ILN has a trId
    339                    at the start, and NLN has a capability field at the end.
    340                    Does ILN still exist BTW? */
    341                 if (cmd[0][1] == 'I') {
    342                         cmd++;
    343                 } else {
    344                         cap = atoi(cmd[4]);
    345                 }
    346 
    347                 handle = msn_normalize_handle(cmd[2]);
    348                 if (strcmp(handle, ic->acc->user) == 0) {
    349                         return 1; /* That's me! */
    350 
    351                 }
    352                 http_decode(cmd[3]);
    353                 imcb_rename_buddy(ic, handle, cmd[3]);
    354 
    355                 st = msn_away_state_by_code(cmd[1]);
    356                 if (!st) {
    357                         /* FIXME: Warn/Bomb about unknown away state? */
    358                         st = msn_away_state_list + 1;
    359                 }
    360 
    361                 imcb_buddy_status(ic, handle, OPT_LOGGED_IN |
    362                                   (st != msn_away_state_list ? OPT_AWAY : 0) |
    363                                   (cap & 1 ? OPT_MOBILE : 0),
    364                                   st->name, NULL);
    365 
    366                 msn_sb_stop_keepalives(msn_sb_by_handle(ic, handle));
    367         } else if (strcmp(cmd[0], "FLN") == 0) {
    368                 const char *handle;
    369 
    370                 if (cmd[1] == NULL) {
    371                         return 1;
    372                 }
    373 
    374                 handle = msn_normalize_handle(cmd[1]);
    375                 imcb_buddy_status(ic, handle, 0, NULL, NULL);
    376                 msn_sb_start_keepalives(msn_sb_by_handle(ic, handle), TRUE);
    377         } else if (strcmp(cmd[0], "RNG") == 0) {
    378                 struct msn_switchboard *sb;
    379                 char *server;
    380                 int session, port;
    381 
    382                 if (num_parts < 7) {
    383                         imcb_error(ic, "Syntax error");
    384                         imc_logout(ic, TRUE);
    385                         return(0);
    386                 }
    387 
    388                 session = atoi(cmd[1]);
    389 
    390                 server = strchr(cmd[2], ':');
    391                 if (!server) {
    392                         imcb_error(ic, "Syntax error");
    393                         imc_logout(ic, TRUE);
    394                         return(0);
    395                 }
    396                 *server = 0;
    397                 port = atoi(server + 1);
    398                 server = cmd[2];
    399 
    400                 if (strcmp(cmd[3], "CKI") != 0) {
    401                         imcb_error(ic, "Unknown authentication method for switchboard");
    402                         imc_logout(ic, TRUE);
    403                         return(0);
    404                 }
    405 
    406                 debug("Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4]);
    407 
    408                 if ((sb = msn_sb_create(ic, server, port, cmd[4], session)) == NULL) {
    409                         /* Although this isn't strictly fatal for the NS connection, it's
    410                            definitely something serious (we ran out of file descriptors?). */
    411                         imcb_error(ic, "Could not create new switchboard");
    412                         imc_logout(ic, TRUE);
    413                         return(0);
    414                 } else {
    415                         sb->who = g_strdup(msn_normalize_handle(cmd[5]));
    416                 }
     302        } else if (strcmp(cmd[0], "QRY") == 0) {
     303                /* CONGRATULATIONS */
    417304        } else if (strcmp(cmd[0], "OUT") == 0) {
    418                 int allow_reconnect = TRUE;
    419 
    420                 if (cmd[1] && strcmp(cmd[1], "OTH") == 0) {
    421                         imcb_error(ic, "Someone else logged in with your account");
    422                         allow_reconnect = FALSE;
    423                 } else if (cmd[1] && strcmp(cmd[1], "SSD") == 0) {
    424                         imcb_error(ic, "Terminating session because of server shutdown");
    425                 } else {
    426                         imcb_error(ic, "Session terminated by remote server (%s)",
    427                                    cmd[1] ? cmd[1] : "reason unknown)");
    428                 }
    429 
    430                 imc_logout(ic, allow_reconnect);
     305                imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown");
     306                imc_logout(ic, TRUE);
    431307                return(0);
    432         } else if (strcmp(cmd[0], "IPG") == 0) {
    433                 imcb_error(ic, "Received IPG command, we don't handle them yet.");
    434 
    435                 handler->msglen = atoi(cmd[1]);
    436 
    437                 if (handler->msglen <= 0) {
    438                         imcb_error(ic, "Syntax error");
    439                         imc_logout(ic, TRUE);
    440                         return(0);
    441                 }
    442         }
    443 #if 0
    444         else if (strcmp(cmd[0], "ADG") == 0) {
    445                 char *group = g_strdup(cmd[3]);
    446                 int groupnum, i;
    447                 GSList *l, *next;
    448 
    449                 http_decode(group);
    450                 if (sscanf(cmd[4], "%d", &groupnum) == 1) {
    451                         if (groupnum >= md->groupcount) {
    452                                 md->grouplist = g_renew(char *, md->grouplist, groupnum + 1);
    453                                 for (i = md->groupcount; i <= groupnum; i++) {
    454                                         md->grouplist[i] = NULL;
    455                                 }
    456                                 md->groupcount = groupnum + 1;
    457                         }
    458                         g_free(md->grouplist[groupnum]);
    459                         md->grouplist[groupnum] = group;
    460                 } else {
    461                         /* Shouldn't happen, but if it does, give up on the group. */
    462                         g_free(group);
    463                         imcb_error(ic, "Syntax error");
    464                         imc_logout(ic, TRUE);
    465                         return 0;
    466                 }
    467 
    468                 for (l = md->grpq; l; l = next) {
    469                         struct msn_groupadd *ga = l->data;
    470                         next = l->next;
    471                         if (g_strcasecmp(ga->group, group) == 0) {
    472                                 if (!msn_buddy_list_add(ic, "FL", ga->who, ga->who, group)) {
    473                                         return 0;
    474                                 }
    475 
    476                                 g_free(ga->group);
    477                                 g_free(ga->who);
    478                                 g_free(ga);
    479                                 md->grpq = g_slist_remove(md->grpq, ga);
    480                         }
    481                 }
    482         }
    483 #endif
    484         else if (strcmp(cmd[0], "GCF") == 0) {
     308        } else if (strcmp(cmd[0], "GCF") == 0) {
    485309                /* Coming up is cmd[2] bytes of stuff we're supposed to
    486310                   censore. Meh. */
    487                 handler->msglen = atoi(cmd[2]);
    488         } else if (strcmp(cmd[0], "UBX") == 0) {
    489                 /* Status message. */
     311                md->msglen = atoi(cmd[2]);
     312        } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) {
    490313                if (num_parts >= 3) {
    491                         handler->msglen = atoi(cmd[2]);
     314                        md->msglen = atoi(cmd[2]);
     315                }
     316        } else if (strcmp(cmd[0], "PUT") == 0) {
     317                if (num_parts >= 4) {
     318                        md->msglen = atoi(cmd[3]);
    492319                }
    493320        } else if (strcmp(cmd[0], "NOT") == 0) {
    494                 /* Some kind of notification, poorly documented but
    495                    apparently used to announce address book changes. */
    496321                if (num_parts >= 2) {
    497                         handler->msglen = atoi(cmd[1]);
    498                 }
    499         } else if (strcmp(cmd[0], "UBM") == 0) {
    500                 if (num_parts >= 7) {
    501                         handler->msglen = atoi(cmd[6]);
     322                        md->msglen = atoi(cmd[1]);
    502323                }
    503324        } else if (strcmp(cmd[0], "QNG") == 0) {
     
    516337                /* Oh yes, errors can have payloads too now. Discard them for now. */
    517338                if (num_parts >= 3) {
    518                         handler->msglen = atoi(cmd[2]);
     339                        md->msglen = atoi(cmd[2]);
    519340                }
    520341        } else {
    521                 /* debug( "Received unknown command from main server: %s", cmd[0] ); */
     342                imcb_error(ic, "Received unknown command from main server: %s", cmd[0]);
    522343        }
    523344
     
    525346}
    526347
    527 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)
    528 {
    529         struct im_connection *ic = handler->data;
     348int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts)
     349{
     350        struct im_connection *ic = md->ic;
    530351        char *body;
    531352        int blen = 0;
     
    598419                                }
    599420                        } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) {
    600                         } else if (g_strncasecmp(ct, "text/x-msmsgsinitialmdatanotification", 37) == 0 ||
    601                                    g_strncasecmp(ct, "text/x-msmsgsoimnotification", 28) == 0) {
    602                                 /* We received an offline message. Or at least notification
    603                                    that there is one waiting for us. Fetching the message(s)
    604                                    and purging them from the server is a lot of SOAPy work
    605                                    not worth doing IMHO. Also I thought it was possible to
    606                                    have the notification server send them directly, I was
    607                                    pretty sure I saw Pidgin do it..
    608 
    609                                    At least give a notification for now, seems like a
    610                                    reasonable thing to do. Only problem is, they'll keep
    611                                    coming back at login time until you read them using a
    612                                    different client. :-( */
    613 
    614                                 char *xml = get_rfc822_header(body, "Mail-Data:", blen);
    615                                 struct xt_node *md, *m;
    616 
    617                                 if (!xml) {
    618                                         return 1;
    619                                 }
    620                                 md = xt_from_string(xml, 0);
    621                                 if (!md) {
    622                                         return 1;
    623                                 }
    624 
    625                                 for (m = md->children; (m = xt_find_node(m, "M")); m = m->next) {
    626                                         struct xt_node *e = xt_find_node(m->children, "E");
    627                                         struct xt_node *rt = xt_find_node(m->children, "RT");
    628                                         struct tm tp;
    629                                         time_t msgtime = 0;
    630 
    631                                         if (!e || !e->text) {
    632                                                 continue;
    633                                         }
    634 
    635                                         memset(&tp, 0, sizeof(tp));
    636                                         if (rt && rt->text &&
    637                                             sscanf(rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.",
    638                                                    &tp.tm_year, &tp.tm_mon, &tp.tm_mday,
    639                                                    &tp.tm_hour, &tp.tm_min, &tp.tm_sec) == 6) {
    640                                                 tp.tm_year -= 1900;
    641                                                 tp.tm_mon--;
    642                                                 msgtime = mktime_utc(&tp);
    643 
    644                                         }
    645                                         imcb_buddy_msg(ic, e->text,
    646                                                        "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0,
    647                                                        msgtime);
    648                                 }
    649 
    650                                 g_free(xml);
    651                                 xt_free_node(md);
     421                                /* Notification that a message has been read... Ignore it */
    652422                        } else {
    653423                                debug("Can't handle %s packet from notification server", ct);
     
    656426                        g_free(ct);
    657427                }
    658         } else if (strcmp(cmd[0], "UBX") == 0) {
    659                 struct xt_node *ubx, *psm;
    660                 char *psm_text = NULL;
    661 
    662                 ubx = xt_from_string(msg, msglen);
    663                 if (ubx && strcmp(ubx->name, "Data") == 0 &&
    664                     (psm = xt_find_node(ubx->children, "PSM"))) {
    665                         psm_text = psm->text;
    666                 }
    667 
    668                 imcb_buddy_status_msg(ic, msn_normalize_handle(cmd[1]), psm_text);
    669                 xt_free_node(ubx);
    670428        } else if (strcmp(cmd[0], "ADL") == 0) {
    671429                struct xt_node *adl, *d, *c;
     
    716474                        }
    717475                }
    718         } else if (strcmp(cmd[0], "UBM") == 0) {
    719                 /* This one will give us msgs from federated networks. Technically
    720                    it should also get us offline messages, but I don't know how
    721                    I can signal MSN servers to use it. */
    722                 char *ct, *handle;
    723 
    724                 if (strcmp(cmd[1], ic->acc->user) == 0) {
    725                         /* With MPOP, you'll get copies of your own msgs from other
    726                            sessions. Discard those at least for now. */
    727                         return 1;
    728                 }
    729 
    730                 ct = get_rfc822_header(msg, "Content-Type", msglen);
    731                 if (strncmp(ct, "text/plain", 10) != 0) {
    732                         /* Typing notification or something? */
    733                         g_free(ct);
    734                         return 1;
    735                 }
    736                 if (strcmp(cmd[2], "1") != 0) {
    737                         handle = g_strdup_printf("%s:%s", cmd[2], cmd[1]);
    738                 } else {
    739                         handle = g_strdup(cmd[1]);
    740                 }
    741 
    742                 imcb_buddy_msg(ic, handle, body, 0, 0);
    743                 g_free(handle);
     476        } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) {
     477                msn_ns_structured_message(md, msg, msglen, cmd);
    744478        }
    745479
    746480        return 1;
     481}
     482
     483static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd)
     484{
     485        char **parts = NULL;
     486        char *semicolon = NULL;
     487        char *action = NULL;
     488        char *from = NULL;
     489        char *who = NULL;
     490
     491        parts = g_strsplit(msg, "\r\n\r\n", 4);
     492
     493        if (!(from = get_rfc822_header(parts[0], "From", 0))) {
     494                goto cleanup;
     495        }
     496
     497        /* either the semicolon or the end of the string */
     498        semicolon = strchr(from, ';') ? : (from + strlen(from));
     499
     500        who = g_strndup(from + 2, semicolon - from - 2);
     501
     502        if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) {
     503                msn_ns_sdg(md, who, parts, action);
     504
     505        } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) {
     506                gboolean is_put = (strcmp(cmd[1], "PUT") == 0);
     507                msn_ns_nfy(md, who, parts, action, is_put);
     508        }
     509
     510cleanup:
     511        g_strfreev(parts);
     512        g_free(action);
     513        g_free(from);
     514        g_free(who);
     515}
     516
     517static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action)
     518{
     519        struct im_connection *ic = md->ic;
     520
     521        if (strcmp(action, "Control/Typing") == 0) {
     522                imcb_buddy_typing(ic, who, OPT_TYPING);
     523        } else if (strcmp(action, "Text") == 0) {
     524                imcb_buddy_msg(ic, who, parts[3], 0, 0);
     525        }
     526}
     527
     528static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put)
     529{
     530        struct im_connection *ic = md->ic;
     531        struct xt_node *body = NULL;
     532        struct xt_node *s = NULL;
     533        const char *state = NULL;
     534        char *nick = NULL;
     535        char *psm = NULL;
     536        int flags = OPT_LOGGED_IN;
     537
     538        if (strcmp(action, "/user") != 0) {
     539                return;
     540        }
     541
     542        if (!(body = xt_from_string(parts[3], 0))) {
     543                goto cleanup;
     544        }
     545
     546        s = body->children;
     547        while ((s = xt_find_node(s, "s"))) {
     548                struct xt_node *s2;
     549                char *n = xt_find_attr(s, "n");  /* service name: IM, PE, etc */
     550
     551                if (strcmp(n, "IM") == 0) {
     552                        /* IM has basic presence information */
     553                        if (!is_put) {
     554                                /* NFY DEL with a <s> usually means log out from the last endpoint */
     555                                flags &= ~OPT_LOGGED_IN;
     556                                break;
     557                        }
     558
     559                        s2 = xt_find_node(s->children, "Status");
     560                        if (s2 && s2->text_len) {
     561                                const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text);
     562                                state = msn_state->name;
     563                                if (msn_state != msn_away_state_list) {
     564                                        flags |= OPT_AWAY;
     565                                }
     566                        }
     567                } else if (strcmp(n, "PE") == 0) {
     568                        if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) {
     569                                psm = s2->text;
     570                        }
     571                        if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) {
     572                                nick = s2->text;
     573                        }
     574                }
     575                s = s->next;
     576        }
     577
     578        imcb_buddy_status(ic, who, flags, state, psm);
     579
     580        if (nick) {
     581                imcb_rename_buddy(ic, who, nick);
     582        }
     583
     584cleanup:
     585        xt_free_node(body);
    747586}
    748587
     
    768607void msn_auth_got_contact_list(struct im_connection *ic)
    769608{
    770         struct msn_data *md;
    771 
    772609        /* Dead connection? */
    773610        if (g_slist_find(msn_connections, ic) == NULL) {
     
    775612        }
    776613
    777         md = ic->proto_data;
    778         msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");
     614        msn_ns_send_adl_start(ic);
     615        msn_ns_finish_login(ic);
    779616}
    780617
    781618static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data)
    782619{
    783         struct xt_node *adl = data, *d, *c;
     620        struct xt_node *adl = data, *d, *c, *s;
    784621        struct bee_user *bu = value;
    785622        struct msn_buddy_data *bd = bu->data;
     
    810647        c = xt_new_node("c", NULL, NULL);
    811648        xt_add_attr(c, "n", handle);
    812         xt_add_attr(c, "l", l);
    813649        xt_add_attr(c, "t", "1");   /* FIXME: Network type, i.e. 32 for Y!MSG */
     650        s = xt_new_node("s", NULL, NULL);
     651        xt_add_attr(s, "n", "IM");
     652        xt_add_attr(s, "l", l);
     653        xt_insert_child(c, s);
    814654        xt_insert_child(d, c);
    815655
     
    881721
    882722        if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) {
    883                 if (md->flags & MSN_EMAIL_UNVERIFIED) {
    884                         imcb_connected(ic);
    885                 } else {
    886                         return msn_ns_set_display_name(ic, set_getstr(&ic->acc->set, "display_name"));
    887                 }
     723                imcb_connected(ic);
    888724        }
    889725
     
    891727}
    892728
     729// TODO: typing notifications, nudges lol, etc
    893730int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text)
    894731{
    895732        struct msn_data *md = ic->proto_data;
    896         int type = 0;
    897         char *buf, *handle;
     733        int retval = 0;
     734        char *buf;
    898735
    899736        if (strncmp(text, "\r\r\r", 3) == 0) {
     
    903740        }
    904741
    905         /* This might be a federated contact. Get its network number,
    906            prefixed to bu->handle with a colon. Default is 1. */
    907         for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) {
    908                 type = type * 10 + *handle - '0';
    909         }
    910         if (*handle == ':') {
    911                 handle++;
    912         } else {
    913                 type = 1;
    914         }
    915 
    916         buf = g_strdup_printf("%s%s", MSN_MESSAGE_HEADERS, text);
    917 
    918         if (msn_ns_write(ic, -1, "UUM %d %s %d %d %zd\r\n%s",
    919                          ++md->trId, handle, type,
    920                          1,          /* type == IM (not nudge/typing) */
    921                          strlen(buf), buf)) {
    922                 return 1;
    923         } else {
    924                 return 0;
    925         }
    926 }
    927 
    928 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq)
    929 {
    930         GSList *l;
    931 
    932         for (l = *msgq; l; l = l->next) {
    933                 struct msn_message *m = l->data;
    934                 bee_user_t *bu = bee_user_by_handle(ic->bee, ic, m->who);
    935 
    936                 if (bu) {
    937                         if (!msn_ns_sendmessage(ic, bu, m->text)) {
    938                                 return;
    939                         }
    940                 }
    941         }
    942 
    943         while (*msgq != NULL) {
    944                 struct msn_message *m = (*msgq)->data;
    945 
    946                 g_free(m->who);
    947                 g_free(m->text);
    948                 g_free(m);
    949 
    950                 *msgq = g_slist_remove(*msgq, m);
    951         }
    952 }
     742        buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, strlen(text), text);
     743        retval = msn_ns_write(ic, -1, "SDG %d %zd\r\n%s", ++md->trId, strlen(buf), buf);
     744        g_free(buf);
     745        return retval;
     746}
  • protocols/msn/soap.c

    r531eabd rb1dc403  
    209209                return;
    210210        }
     211        fprintf(stderr, "\n\x1b[90mSOAP:\n");
    211212
    212213        if (headers) {
     
    225226                xt_free_node(xt);
    226227        }
     228        fprintf(stderr, "\n\x1b[97m\n");
    227229}
    228230
  • protocols/msn/soap.h

    r531eabd rb1dc403  
    167167
    168168#define SOAP_MEMLIST_PAYLOAD \
    169         "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\"><Types xmlns=\"http://www.msn.com/webservices/AddressBook\"><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType></Types></serviceFilter>" \
     169        "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter><Types><ServiceType>Messenger</ServiceType><ServiceType>IMAvailability</ServiceType></Types></serviceFilter><expandMembership>true</expandMembership>" \
    170170        "</FindMembership>"
    171171
  • protocols/msn/tables.c

    r531eabd rb1dc403  
    7373        { 206, "Domain name missing",                                   0 },
    7474        { 207, "Already logged in",                                     0 },
    75         { 208, "Invalid handle",                                        STATUS_SB_IM_SPARE },
     75        { 208, "Invalid handle",                                        0 },
    7676        { 209, "Forbidden nickname",                                    0 },
    7777        { 210, "Buddy list too long",                                   0 },
    7878        { 215, "Handle is already in list",                             0 },
    79         { 216, "Handle is not in list",                                 STATUS_SB_IM_SPARE },
    80         { 217, "Person is off-line or non-existent",                    STATUS_SB_IM_SPARE },
     79        { 216, "Handle is not in list",                                 0 },
     80        { 217, "Person is off-line or non-existent",                    0 },
    8181        { 218, "Already in that mode",                                  0 },
    8282        { 219, "Handle is already in opposite list",                    0 },
     
    113113        { 711, "Write is blocking",                                     STATUS_FATAL },
    114114        { 712, "Session is overloaded",                                 STATUS_FATAL },
    115         { 713, "Calling too rapidly",                                   STATUS_SB_IM_SPARE },
     115        { 713, "Calling too rapidly",                                   0 },
    116116        { 714, "Too many sessions",                                     STATUS_FATAL },
    117117        { 715, "Not expected/Invalid argument/action",                  0 },
  • protocols/nogaim.c

    r531eabd rb1dc403  
    503503};
    504504
    505 static void imcb_ask_auth_cb_no(void *data)
     505static void imcb_ask_cb_free(void *data)
    506506{
    507507        struct imcb_ask_cb_data *cbd = data;
    508 
    509         cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);
    510508
    511509        g_free(cbd->handle);
     
    513511}
    514512
     513static void imcb_ask_auth_cb_no(void *data)
     514{
     515        struct imcb_ask_cb_data *cbd = data;
     516
     517        cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);
     518
     519        imcb_ask_cb_free(cbd);
     520}
     521
    515522static void imcb_ask_auth_cb_yes(void *data)
    516523{
     
    519526        cbd->ic->acc->prpl->auth_allow(cbd->ic, cbd->handle);
    520527
    521         g_free(cbd->handle);
    522         g_free(cbd);
     528        imcb_ask_cb_free(cbd);
    523529}
    524530
     
    540546        data->handle = g_strdup(handle);
    541547        query_add((irc_t *) ic->bee->ui_data, ic, s,
    542                   imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, g_free, data);
    543 }
    544 
    545 
    546 static void imcb_ask_add_cb_no(void *data)
    547 {
    548         g_free(((struct imcb_ask_cb_data*) data)->handle);
    549         g_free(data);
     548                  imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, imcb_ask_cb_free, data);
     549
     550        g_free(s);
    550551}
    551552
     
    556557        cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
    557558
    558         imcb_ask_add_cb_no(data);
     559        imcb_ask_cb_free(data);
    559560}
    560561
    561562void imcb_ask_add(struct im_connection *ic, const char *handle, const char *realname)
    562563{
    563         struct imcb_ask_cb_data *data = g_new0(struct imcb_ask_cb_data, 1);
     564        struct imcb_ask_cb_data *data;
    564565        char *s;
    565566
     
    569570        }
    570571
     572        data = g_new0(struct imcb_ask_cb_data, 1);
     573
    571574        s = g_strdup_printf("The user %s is not in your buddy list yet. Do you want to add him/her now?", handle);
    572575
     
    574577        data->handle = g_strdup(handle);
    575578        query_add((irc_t *) ic->bee->ui_data, ic, s,
    576                   imcb_ask_add_cb_yes, imcb_ask_add_cb_no, g_free, data);
     579                  imcb_ask_add_cb_yes, imcb_ask_cb_free, imcb_ask_cb_free, data);
     580
     581        g_free(s);
    577582}
    578583
  • protocols/purple/ft-direct.c

    r531eabd rb1dc403  
    2828
    2929#include "bitlbee.h"
     30#include "bpurple.h"
    3031
    3132#include <stdarg.h>
     
    207208void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle)
    208209{
    209         PurpleAccount *pa = ic->proto_data;
     210        struct purple_data *pd = ic->proto_data;
    210211        struct prpl_xfer_data *px;
    211212
     
    213214           multi-threaded anyway. */
    214215        next_ft = ft;
    215         serv_send_file(purple_account_get_connection(pa), handle, ft->file_name);
     216        serv_send_file(purple_account_get_connection(pd->account), handle,
     217                       ft->file_name);
    216218
    217219        ft->write = prpl_xfer_write;
  • protocols/purple/ft.c

    r531eabd rb1dc403  
    2828
    2929#include "bitlbee.h"
     30#include "bpurple.h"
    3031
    3132#include <stdarg.h>
     
    285286{
    286287        struct prpl_xfer_data *px = ft->data;
    287         PurpleAccount *pa = px->ic->proto_data;
     288        struct purple_data *pd = px->ic->proto_data;
    288289
    289290        /* xfer_new() will pick up this variable. It's a hack but we're not
    290291           multi-threaded anyway. */
    291292        next_ft = ft;
    292         serv_send_file(purple_account_get_connection(pa), px->handle, px->fn);
     293        serv_send_file(purple_account_get_connection(pd->account),
     294                   px->handle, px->fn);
    293295}
    294296
  • protocols/purple/purple.c

    r531eabd rb1dc403  
    2323
    2424#include "bitlbee.h"
     25#include "bpurple.h"
    2526#include "help.h"
    2627
     
    3940static char *set_eval_display_name(set_t *set, char *value);
    4041
     42void purple_request_input_callback(guint id, struct im_connection *ic,
     43                                   const char *message, const char *who);
     44
     45/* purple_request_input specific stuff */
     46typedef void (*ri_callback_t)(gpointer, const gchar *);
     47
     48struct request_input_data {
     49        ri_callback_t data_callback;
     50        void *user_data;
     51        struct im_connection *ic;
     52        char *buddy;
     53        guint id;
     54};
     55
    4156struct im_connection *purple_ic_by_pa(PurpleAccount *pa)
    4257{
    4358        GSList *i;
     59        struct purple_data *pd;
    4460
    4561        for (i = purple_connections; i; i = i->next) {
    46                 if (((struct im_connection *) i->data)->proto_data == pa) {
     62                pd = ((struct im_connection *) i->data)->proto_data;
     63                if (pd->account == pa) {
    4764                        return i->data;
    4865                }
     
    290307{
    291308        struct im_connection *ic = imcb_new(acc);
    292         PurpleAccount *pa;
     309        struct purple_data *pd;
    293310
    294311        if ((local_bee != NULL && local_bee != acc->bee) ||
     
    306323        purple_connections = g_slist_prepend(purple_connections, ic);
    307324
    308         ic->proto_data = pa = purple_account_new(acc->user, (char *) acc->prpl->data);
    309         purple_account_set_password(pa, acc->pass);
    310         purple_sync_settings(acc, pa);
    311 
    312         purple_account_set_enabled(pa, "BitlBee", TRUE);
     325        ic->proto_data = pd = g_new0(struct purple_data, 1);
     326        pd->account = purple_account_new(acc->user, (char *) acc->prpl->data);
     327        pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal,
     328                                                   NULL, g_free);
     329        pd->next_request_id = 0;
     330        purple_account_set_password(pd->account, acc->pass);
     331        purple_sync_settings(acc, pd->account);
     332
     333        purple_account_set_enabled(pd->account, "BitlBee", TRUE);
    313334}
    314335
    315336static void purple_logout(struct im_connection *ic)
    316337{
    317         PurpleAccount *pa = ic->proto_data;
    318 
    319         purple_account_set_enabled(pa, "BitlBee", FALSE);
     338        struct purple_data *pd = ic->proto_data;
     339
     340        if (!pd) {
     341                return;
     342        }
     343
     344        purple_account_set_enabled(pd->account, "BitlBee", FALSE);
    320345        purple_connections = g_slist_remove(purple_connections, ic);
    321         purple_accounts_remove(pa);
     346        purple_accounts_remove(pd->account);
     347        g_hash_table_destroy(pd->input_requests);
     348        g_free(pd);
    322349}
    323350
     
    325352{
    326353        PurpleConversation *conv;
     354        struct purple_data *pd = ic->proto_data;
     355
     356        if (!strncmp(who, PURPLE_REQUEST_HANDLE, sizeof(PURPLE_REQUEST_HANDLE) - 1)) {
     357                guint request_id = atoi(who + sizeof(PURPLE_REQUEST_HANDLE));
     358                purple_request_input_callback(request_id, ic, message, who);
     359                return 1;
     360        }
    327361
    328362        if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
    329                                                           who, ic->proto_data)) == NULL) {
     363                                                          who, pd->account)) == NULL) {
    330364                conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
    331                                                ic->proto_data, who);
     365                                               pd->account, who);
    332366        }
    333367
     
    339373static GList *purple_away_states(struct im_connection *ic)
    340374{
    341         PurpleAccount *pa = ic->proto_data;
     375        struct purple_data *pd = ic->proto_data;
    342376        GList *st, *ret = NULL;
    343377
    344         for (st = purple_account_get_status_types(pa); st; st = st->next) {
     378        for (st = purple_account_get_status_types(pd->account); st; st = st->next) {
    345379                PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data);
    346380                if (prim != PURPLE_STATUS_AVAILABLE && prim != PURPLE_STATUS_OFFLINE) {
     
    354388static void purple_set_away(struct im_connection *ic, char *state_txt, char *message)
    355389{
    356         PurpleAccount *pa = ic->proto_data;
    357         GList *status_types = purple_account_get_status_types(pa), *st;
     390        struct purple_data *pd = ic->proto_data;
     391        GList *status_types = purple_account_get_status_types(pd->account), *st;
    358392        PurpleStatusType *pst = NULL;
    359393        GList *args = NULL;
     
    378412        }
    379413
    380         purple_account_set_status_list(pa, st ? purple_status_type_get_id(pst) : "away",
     414        purple_account_set_status_list(pd->account,
     415                                       st ? purple_status_type_get_id(pst) : "away",
    381416                                       TRUE, args);
    382417
     
    447482        PurpleBuddy *pb;
    448483        PurpleGroup *pg = NULL;
     484        struct purple_data *pd = ic->proto_data;
    449485
    450486        if (group && !(pg = purple_find_group(group))) {
     
    453489        }
    454490
    455         pb = purple_buddy_new((PurpleAccount *) ic->proto_data, who, NULL);
     491        pb = purple_buddy_new(pd->account, who, NULL);
    456492        purple_blist_add_buddy(pb, NULL, pg, NULL);
    457         purple_account_add_buddy((PurpleAccount *) ic->proto_data, pb);
    458 
    459         purple_gg_buddylist_export(((PurpleAccount *) ic->proto_data)->gc);
     493        purple_account_add_buddy(pd->account, pb);
     494
     495        purple_gg_buddylist_export(pd->account->gc);
    460496}
    461497
     
    463499{
    464500        PurpleBuddy *pb;
    465 
    466         pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who);
     501        struct purple_data *pd = ic->proto_data;
     502
     503        pb = purple_find_buddy(pd->account, who);
    467504        if (pb != NULL) {
    468505                PurpleGroup *group;
    469506
    470507                group = purple_buddy_get_group(pb);
    471                 purple_account_remove_buddy((PurpleAccount *) ic->proto_data, pb, group);
     508                purple_account_remove_buddy(pd->account, pb, group);
    472509
    473510                purple_blist_remove_buddy(pb);
    474511        }
    475512
    476         purple_gg_buddylist_export(((PurpleAccount *) ic->proto_data)->gc);
     513        purple_gg_buddylist_export(pd->account->gc);
    477514}
    478515
    479516static void purple_add_permit(struct im_connection *ic, char *who)
    480517{
    481         PurpleAccount *pa = ic->proto_data;
    482 
    483         purple_privacy_permit_add(pa, who, FALSE);
     518        struct purple_data *pd = ic->proto_data;
     519
     520        purple_privacy_permit_add(pd->account, who, FALSE);
    484521}
    485522
    486523static void purple_add_deny(struct im_connection *ic, char *who)
    487524{
    488         PurpleAccount *pa = ic->proto_data;
    489 
    490         purple_privacy_deny_add(pa, who, FALSE);
     525        struct purple_data *pd = ic->proto_data;
     526
     527        purple_privacy_deny_add(pd->account, who, FALSE);
    491528}
    492529
    493530static void purple_rem_permit(struct im_connection *ic, char *who)
    494531{
    495         PurpleAccount *pa = ic->proto_data;
    496 
    497         purple_privacy_permit_remove(pa, who, FALSE);
     532        struct purple_data *pd = ic->proto_data;
     533
     534        purple_privacy_permit_remove(pd->account, who, FALSE);
    498535}
    499536
    500537static void purple_rem_deny(struct im_connection *ic, char *who)
    501538{
    502         PurpleAccount *pa = ic->proto_data;
    503 
    504         purple_privacy_deny_remove(pa, who, FALSE);
     539        struct purple_data *pd = ic->proto_data;
     540
     541        purple_privacy_deny_remove(pd->account, who, FALSE);
    505542}
    506543
    507544static void purple_get_info(struct im_connection *ic, char *who)
    508545{
    509         serv_get_info(purple_account_get_connection(ic->proto_data), who);
     546        struct purple_data *pd = ic->proto_data;
     547
     548        serv_get_info(purple_account_get_connection(pd->account), who);
    510549}
    511550
     
    517556{
    518557        PurpleTypingState state = PURPLE_NOT_TYPING;
    519         PurpleAccount *pa = ic->proto_data;
     558        struct purple_data *pd = ic->proto_data;
    520559
    521560        if (flags & OPT_TYPING) {
     
    525564        }
    526565
    527         serv_send_typing(purple_account_get_connection(pa), who, state);
     566        serv_send_typing(purple_account_get_connection(pd->account), who, state);
    528567
    529568        return 1;
     
    559598        /* There went my nice afternoon. :-( */
    560599
    561         PurpleAccount *pa = ic->proto_data;
    562         PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id);
     600        struct purple_data *pd = ic->proto_data;
     601        PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id);
    563602        PurplePluginProtocolInfo *pi = prpl->info->extra_info;
    564         PurpleBuddy *pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who);
     603        PurpleBuddy *pb = purple_find_buddy(pd->account, who);
    565604        PurpleMenuAction *mi;
    566605        GList *menu;
     
    597636        PurpleConversation *pc = gc->data;
    598637        PurpleConvChat *pcc = PURPLE_CONV_CHAT(pc);
    599 
    600         serv_chat_invite(purple_account_get_connection(gc->ic->proto_data),
     638        struct purple_data *pd = gc->ic->proto_data;
     639
     640        serv_chat_invite(purple_account_get_connection(pd->account),
    601641                         purple_conv_chat_get_id(pcc),
    602642                         message && *message ? message : "Please join my chat",
     
    623663                                   set_t **sets)
    624664{
    625         PurpleAccount *pa = ic->proto_data;
    626         PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id);
     665        struct purple_data *pd = ic->proto_data;
     666        PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id);
    627667        PurplePluginProtocolInfo *pi = prpl->info->extra_info;
    628668        GHashTable *chat_hash;
     
    631671
    632672        if (!pi->chat_info || !pi->chat_info_defaults ||
    633             !(info = pi->chat_info(purple_account_get_connection(pa)))) {
     673            !(info = pi->chat_info(purple_account_get_connection(pd->account)))) {
    634674                imcb_error(ic, "Joining chatrooms not supported by this protocol");
    635675                return NULL;
    636676        }
    637677
    638         if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room, pa))) {
     678        if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
     679                                                          room, pd->account))) {
    639680                purple_conversation_destroy(conv);
    640681        }
    641682
    642         chat_hash = pi->chat_info_defaults(purple_account_get_connection(pa), room);
     683        chat_hash = pi->chat_info_defaults(
     684                purple_account_get_connection(pd->account), room
     685        );
    643686
    644687        for (l = info; l; l = l->next) {
     
    654697        }
    655698
    656         serv_join_chat(purple_account_get_connection(pa), chat_hash);
     699        serv_join_chat(purple_account_get_connection(pd->account), chat_hash);
    657700
    658701        return NULL;
     
    9811024                pqad->yes(pqad->user_data, pqad->yes_i);
    9821025        }
    983         g_free(pqad);
    9841026}
    9851027
     
    9911033                pqad->no(pqad->user_data, pqad->no_i);
    9921034        }
    993         g_free(pqad);
     1035}
     1036
     1037/* q->free() callback from query_del()*/
     1038static void prplcb_request_action_free(void *data)
     1039{
     1040        struct prplcb_request_action_data *pqad = data;
     1041
     1042        pqad->bee_data = NULL;
     1043        purple_request_close(PURPLE_REQUEST_ACTION, pqad);
    9941044}
    9951045
     
    10261076        q = g_strdup_printf("Request: %s\n\n%s\n\n%s", title, primary, secondary);
    10271077        pqad->bee_data = query_add(local_bee->ui_data, purple_ic_by_pa(account), q,
    1028                                    prplcb_request_action_yes, prplcb_request_action_no, g_free, pqad);
     1078                                   prplcb_request_action_yes, prplcb_request_action_no,
     1079                                   prplcb_request_action_free, pqad);
    10291080
    10301081        g_free(q);
     
    10331084}
    10341085
    1035 /*
    1036 static void prplcb_request_test()
    1037 {
    1038         fprintf( stderr, "bla\n" );
    1039 }
    1040 */
     1086/* So it turns out some requests have no account context at all, because
     1087 * libpurple hates us. This means that query_del_by_conn() won't remove those
     1088 * on logout, and will segfault if the user replies. That's why this exists.
     1089 */
     1090static void prplcb_close_request(PurpleRequestType type, void *data)
     1091{
     1092        struct prplcb_request_action_data *pqad;
     1093        struct request_input_data *ri;
     1094        struct purple_data *pd;
     1095
     1096        if (!data) {
     1097                return;
     1098        }
     1099
     1100        switch (type) {
     1101        case PURPLE_REQUEST_ACTION:
     1102                pqad = data;
     1103                /* if this is null, it's because query_del was run already */
     1104                if (pqad->bee_data) {
     1105                        query_del(local_bee->ui_data, pqad->bee_data);
     1106                }
     1107                g_free(pqad);
     1108                break;
     1109        case PURPLE_REQUEST_INPUT:
     1110                ri = data;
     1111                pd = ri->ic->proto_data;
     1112                imcb_remove_buddy(ri->ic, ri->buddy, NULL);
     1113                g_free(ri->buddy);
     1114                g_hash_table_remove(pd->input_requests, GUINT_TO_POINTER(ri->id));
     1115                break;
     1116        default:
     1117                g_free(data);
     1118                break;
     1119        }
     1120
     1121}
     1122
     1123void* prplcb_request_input(const char *title, const char *primary,
     1124        const char *secondary, const char *default_value, gboolean multiline,
     1125        gboolean masked, gchar *hint, const char *ok_text, GCallback ok_cb,
     1126        const char *cancel_text, GCallback cancel_cb, PurpleAccount *account,
     1127        const char *who, PurpleConversation *conv, void *user_data)
     1128{
     1129        struct im_connection *ic = purple_ic_by_pa(account);
     1130        struct purple_data *pd = ic->proto_data;
     1131        struct request_input_data *ri = g_new0(struct request_input_data, 1);
     1132        guint id = pd->next_request_id++;
     1133
     1134        ri->id = id;
     1135        ri->ic = ic;
     1136        ri->buddy = g_strdup_printf("%s_%u", PURPLE_REQUEST_HANDLE, id);
     1137        ri->data_callback = (ri_callback_t) ok_cb;
     1138        ri->user_data = user_data;
     1139        g_hash_table_insert(pd->input_requests, GUINT_TO_POINTER(id), ri);
     1140
     1141        imcb_add_buddy(ic, ri->buddy, NULL);
     1142        imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0);
     1143
     1144        return ri;
     1145}
     1146
     1147void purple_request_input_callback(guint id, struct im_connection *ic,
     1148                                   const char *message, const char *who)
     1149{
     1150        struct purple_data *pd = ic->proto_data;
     1151        struct request_input_data *ri;
     1152
     1153        if (!(ri = g_hash_table_lookup(pd->input_requests, GUINT_TO_POINTER(id)))) {
     1154                return;
     1155        }
     1156
     1157        ri->data_callback(ri->user_data, message);
     1158
     1159        purple_request_close(PURPLE_REQUEST_INPUT, ri);
     1160}
     1161
    10411162
    10421163static PurpleRequestUiOps bee_request_uiops =
    10431164{
    1044         NULL,
     1165        prplcb_request_input,
    10451166        NULL,
    10461167        prplcb_request_action,
    10471168        NULL,
    10481169        NULL,
    1049         NULL,
     1170        prplcb_close_request,
    10501171        NULL,
    10511172};
  • protocols/skype/Makefile

    r531eabd rb1dc403  
    66DATE := $(shell date +%Y-%m-%d)
    77INSTALL = install
    8 ASCIIDOC = yes
    98
    10 ifeq ($(ASCIIDOC),yes)
     9
     10ifdef ASCIIDOC
    1111MANPAGES = skyped.1
    1212else
     
    2929
    3030install-doc: doc
    31 ifeq ($(ASCIIDOC),yes)
     31ifdef ASCIIDOC
    3232        $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1
    3333        $(INSTALL) -m644 $(MANPAGES) $(DESTDIR)$(MANDIR)/man1
  • protocols/twitter/twitter.c

    r531eabd rb1dc403  
    852852}
    853853
     854/* Parses a decimal or hex tweet ID, returns TRUE on success */
     855static gboolean twitter_parse_id(char *string, int base, guint64 *id)
     856{
     857        guint64 parsed;
     858        char *endptr;
     859
     860        errno = 0;
     861        parsed = g_ascii_strtoull(string, &endptr, base);
     862        if (errno || endptr == string || *endptr != '\0') {
     863                return FALSE;
     864        }
     865        *id = parsed;
     866        return TRUE;
     867}
     868
     869bee_user_t twitter_log_local_user;
     870
    854871/** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID
    855872 *  into a twitter tweet ID.
     
    879896                        arg++;
    880897                }
    881                 if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1 &&
    882                     id < TWITTER_LOG_LENGTH) {
     898                if (twitter_parse_id(arg, 16, &id) && id < TWITTER_LOG_LENGTH) {
    883899                        bu = td->log[id].bu;
    884900                        id = td->log[id].id;
    885                         /* Beware of dangling pointers! */
    886                         if (!g_slist_find(ic->bee->users, bu)) {
    887                                 bu = NULL;
    888                         }
    889                 } else if (sscanf(arg, "%" G_GINT64_MODIFIER "d", &id) == 1) {
     901                } else if (twitter_parse_id(arg, 10, &id)) {
    890902                        /* Allow normal tweet IDs as well; not a very useful
    891903                           feature but it's always been there. Just ignore
     
    897909        }
    898910        if (bu_) {
     911                if (bu == &twitter_log_local_user) {
     912                        /* HACK alert. There's no bee_user object for the local
     913                         * user so just fake one for the few cmds that need it. */
     914                        twitter_log_local_user.handle = td->user;
     915                } else {
     916                        /* Beware of dangling pointers! */
     917                        if (!g_slist_find(ic->bee->users, bu)) {
     918                                bu = NULL;
     919                        }
     920                }
    899921                *bu_ = bu;
    900922        }
     
    9891011                in_reply_to = id;
    9901012                allow_post = TRUE;
     1013        } else if (g_strcasecmp(cmd[0], "url") == 0) {
     1014                id = twitter_message_id_from_command_arg(ic, cmd[1], &bu);
     1015                if (!id) {
     1016                        twitter_log(ic, "Tweet `%s' does not exist", cmd[1]);
     1017                } else {
     1018                        /* More common link is twitter.com/$UID/status/$ID (and that's
     1019                         * what this will 302 to) but can't generate that since for RTs,
     1020                         * bu here points at the retweeter while id contains the id of
     1021                         * the original message. */
     1022                        twitter_log(ic, "https://twitter.com/statuses/%lld", id);
     1023                }
     1024                goto eof;
     1025
    9911026        } else if (g_strcasecmp(cmd[0], "post") == 0) {
    9921027                message += 5;
  • protocols/twitter/twitter.h

    r531eabd rb1dc403  
    101101struct twitter_log_data {
    102102        guint64 id;
    103         struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */
     103        /* DANGER: bu can be a dead pointer. Check it first.
     104         * twitter_message_id_from_command_arg() will do this. */
     105        struct bee_user *bu;
    104106};
    105107
     
    110112 */
    111113extern GSList *twitter_connections;
     114
     115/**
     116 * Evil hack: Fake bee_user which will always point at the local user.
     117 * Sometimes used as a return value by twitter_message_id_from_command_arg.
     118 * NOT thread safe but don't you dare to even think of ever making BitlBee
     119 * threaded. :-)
     120 */
     121extern bee_user_t twitter_log_local_user;
    112122
    113123void twitter_login_finish(struct im_connection *ic);
  • protocols/twitter/twitter_lib.c

    r531eabd rb1dc403  
    460460#endif
    461461
    462 static char* expand_entities(char* text, const json_value *entities);
     462static void expand_entities(char **text, const json_value *node);
    463463
    464464/**
     
    473473{
    474474        struct twitter_xml_status *txs;
    475         const json_value *rt = NULL, *entities = NULL;
     475        const json_value *rt = NULL;
    476476
    477477        if (node->type != json_object) {
     
    501501                } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
    502502                        txs->reply_to = v->u.integer;
    503                 } else if (strcmp("entities", k) == 0 && v->type == json_object) {
    504                         entities = v;
    505503                }
    506504        }
     
    516514                        txs_free(rtxs);
    517515                }
    518         } else if (entities) {
    519                 txs->text = expand_entities(txs->text, entities);
     516        } else {
     517                expand_entities(&txs->text, node);
    520518        }
    521519
     
    534532{
    535533        struct twitter_xml_status *txs;
    536         const json_value *entities = NULL;
    537534
    538535        if (node->type != json_object) {
     
    561558        }
    562559
    563         if (entities) {
    564                 txs->text = expand_entities(txs->text, entities);
    565         }
     560        expand_entities(&txs->text, node);
    566561
    567562        if (txs->text && txs->user && txs->id) {
     
    573568}
    574569
    575 static char* expand_entities(char* text, const json_value *entities)
    576 {
     570static void expand_entities(char **text, const json_value *node)
     571{
     572        json_value *entities, *quoted;
     573        char *quote_url = NULL, *quote_text = NULL;
     574
     575        if (!((entities = json_o_get(node, "entities")) && entities->type == json_object))
     576                return;
     577        if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) {
     578                /* New "retweets with comments" feature. Note that this info
     579                 * seems to be included in the streaming API only! Grab the
     580                 * full message and try to insert it when we run into the
     581                 * Tweet entity. */
     582                struct twitter_xml_status *txs = twitter_xt_get_status(quoted);
     583                quote_text = g_strdup_printf("@%s: %s", txs->user->screen_name, txs->text);
     584                quote_url = g_strdup_printf("%s/status/%" G_GUINT64_FORMAT, txs->user->screen_name, txs->id);
     585                txs_free(txs);
     586        } else {
     587                quoted = NULL;
     588        }
     589
    577590        JSON_O_FOREACH(entities, k, v) {
    578591                int i;
     
    586599
    587600                for (i = 0; i < v->u.array.length; i++) {
     601                        const char *format = "%s%s <%s>%s";
     602
    588603                        if (v->u.array.values[i]->type != json_object) {
    589604                                continue;
     
    592607                        const char *kort = json_o_str(v->u.array.values[i], "url");
    593608                        const char *disp = json_o_str(v->u.array.values[i], "display_url");
     609                        const char *full = json_o_str(v->u.array.values[i], "expanded_url");
    594610                        char *pos, *new;
    595611
    596                         if (!kort || !disp || !(pos = strstr(text, kort))) {
     612                        if (!kort || !disp || !(pos = strstr(*text, kort))) {
    597613                                continue;
    598614                        }
     615                        if (quote_url && strstr(full, quote_url)) {
     616                                format = "%s<%s> [%s]%s";
     617                                disp = quote_text;
     618                        }
    599619
    600620                        *pos = '\0';
    601                         new = g_strdup_printf("%s%s <%s>%s", text, kort,
     621                        new = g_strdup_printf(format, *text, kort,
    602622                                              disp, pos + strlen(kort));
    603623
    604                         g_free(text);
    605                         text = new;
    606                 }
    607         }
    608 
    609         return text;
     624                        g_free(*text);
     625                        *text = new;
     626                }
     627        }
     628        g_free(quote_text);
     629        g_free(quote_url);
    610630}
    611631
     
    681701        if (g_strcasecmp(txs->user->screen_name, td->user) == 0) {
    682702                td->log[td->log_id].id = txs->rt_id;
     703                /* More useful than NULL. */
     704                td->log[td->log_id].bu = &twitter_log_local_user;
    683705        }
    684706
     
    832854
    833855        last_id_str = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id);
    834         set_setstr(&ic->acc->set, "last_tweet", last_id_str);
     856        set_setstr(&ic->acc->set, "_last_tweet", last_id_str);
    835857        g_free(last_id_str);
    836858}
     
    862884
    863885                imcb_error(ic, "Stream closed (%s)", req->status_string);
     886                if (req->status_code == 401) {
     887                        imcb_error(ic, "Check your system clock.");
     888                }
    864889                imc_logout(ic, TRUE);
    865890                return;
  • protocols/yahoo/yahoo.c

    r531eabd rb1dc403  
    733733                inp = l->data;
    734734                if (inp->h == tag) {
     735                        byahoo_inputs = g_slist_remove(byahoo_inputs, inp);
    735736                        g_free(inp->d);
    736737                        g_free(inp);
    737                         byahoo_inputs = g_slist_remove(byahoo_inputs, inp);
    738738                        break;
    739739                }
Note: See TracChangeset for help on using the changeset viewer.