Changes in / [356e2dd:291c49b]


Ignore:
Files:
1 added
1 deleted
8 edited

Legend:

Unmodified
Added
Removed
  • lib/misc.c

    r356e2dd r291c49b  
    719719                        }
    720720
     721                        /* Make sure we're still inside the string */
     722                        if (i >= len) {
     723                                return(NULL);
     724                        }
     725
    721726                        /* Copy the found data */
    722727                        return(g_strndup(ret, text + i - ret));
  • protocols/msn/Makefile

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

    r356e2dd r291c49b  
    3030int msn_chat_id;
    3131GSList *msn_connections;
     32GSList *msn_switchboards;
    3233
    3334static char *set_eval_display_name(set_t *set, char *value);
     
    4748
    4849        set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
     50        set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);
    4951
    5052        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
     
    6264
    6365        if (!server) {
    64                 server = "geo.gateway.messenger.live.com";
     66                imcb_error(ic, "The msn protocol is disabled in this version because most servers disabled MSNP18 over port 1863.");
     67                imcb_error(ic, "If you find a working server, you can change the 'server' setting of this account. Good luck!");
     68                imcb_error(ic, "See also: http://ismsndeadyet.com/"); // shameless plug
     69                imc_logout(ic, FALSE);
     70                return;
    6571        }
    6672
     
    7480        md->away_state = msn_away_state_list;
    7581        md->domaintree = g_tree_new(msn_domaintree_cmp);
    76         md->fd = -1;
    77         md->is_http = TRUE;
     82        md->ns->fd = -1;
    7883
    7984        msn_connections = g_slist_prepend(msn_connections, ic);
    8085
    8186        imcb_log(ic, "Connecting");
    82         msn_ns_connect(ic, server,
     87        msn_ns_connect(ic, md->ns, server,
    8388                       set_getint(&ic->acc->set, "port"));
    8489}
     
    9196
    9297        if (md) {
    93                 msn_ns_close(md);
    94 
     98                msn_ns_close(md->ns);
     99
     100                while (md->switchboards) {
     101                        msn_sb_destroy(md->switchboards->data);
     102                }
     103
     104                msn_msgq_purge(ic, &md->msgq);
    95105                msn_soapq_flush(ic, FALSE);
    96106
     
    144154{
    145155        struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who);
     156        struct msn_buddy_data *bd = bu ? bu->data : NULL;
     157        struct msn_switchboard *sb;
    146158
    147159#ifdef DEBUG
    148160        if (strcmp(who, "raw") == 0) {
    149161                msn_ns_write(ic, -1, "%s\r\n", message);
    150                 return 0;
    151         }
     162        } else
    152163#endif
    153 
    154         msn_ns_sendmessage(ic, bu, message);
     164        if (bd && bd->flags & MSN_BUDDY_FED) {
     165                msn_ns_sendmessage(ic, bu, message);
     166        } else if ((sb = msn_sb_by_handle(ic, who))) {
     167                return(msn_sb_sendmessage(sb, message));
     168        } else {
     169                struct msn_message *m;
     170
     171                /* Create a message. We have to arrange a usable switchboard, and send the message later. */
     172                m = g_new0(struct msn_message, 1);
     173                m->who = g_strdup(who);
     174                m->text = g_strdup(message);
     175
     176                return msn_sb_write_msg(ic, m);
     177        }
     178
    155179        return(0);
    156180}
     
    174198static void msn_set_away(struct im_connection *ic, char *state, char *message)
    175199{
     200        char *uux;
    176201        struct msn_data *md = ic->proto_data;
    177         char *nick, *psm, *idle, *statecode, *body, *buf;
    178202
    179203        if (state == NULL) {
     
    183207        }
    184208
    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);
     209        if (!msn_ns_write(ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2)) {
     210                return;
     211        }
     212
     213        uux = g_markup_printf_escaped("<EndpointData><Capabilities>%d:%02d"
     214                                      "</Capabilities></EndpointData>",
     215                                      MSN_CAP1, MSN_CAP2);
     216        msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
     217        g_free(uux);
     218
     219        uux = g_markup_printf_escaped("<PrivateEndpointData><EpName>%s</EpName>"
     220                                      "<Idle>%s</Idle><ClientType>%d</ClientType>"
     221                                      "<State>%s</State></PrivateEndpointData>",
     222                                      md->uuid,
     223                                      strcmp(md->away_state->code, "IDL") ? "false" : "true",
     224                                      1,  /* ? */
     225                                      md->away_state->code);
     226        msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
     227        g_free(uux);
     228
     229        uux = g_markup_printf_escaped("<Data><DDP></DDP><PSM>%s</PSM>"
     230                                      "<CurrentMedia></CurrentMedia>"
     231                                      "<MachineGuid>%s</MachineGuid></Data>",
     232                                      message ? message : "", md->uuid);
     233        msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
     234        g_free(uux);
    202235}
    203236
     
    225258static void msn_chat_msg(struct groupchat *c, char *message, int flags)
    226259{
    227         /* TODO: groupchats*/
     260        struct msn_switchboard *sb = msn_sb_by_chat(c);
     261
     262        if (sb) {
     263                msn_sb_sendmessage(sb, message);
     264        }
     265        /* FIXME: Error handling (although this can't happen unless something's
     266           already severely broken) disappeared here! */
    228267}
    229268
    230269static void msn_chat_invite(struct groupchat *c, char *who, char *message)
    231270{
    232         /* TODO: groupchats*/
     271        struct msn_switchboard *sb = msn_sb_by_chat(c);
     272
     273        if (sb) {
     274                msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, who);
     275        }
    233276}
    234277
    235278static void msn_chat_leave(struct groupchat *c)
    236279{
    237         /* TODO: groupchats*/
     280        struct msn_switchboard *sb = msn_sb_by_chat(c);
     281
     282        if (sb) {
     283                msn_sb_write(sb, "OUT\r\n");
     284        }
    238285}
    239286
    240287static struct groupchat *msn_chat_with(struct im_connection *ic, char *who)
    241288{
    242         /* TODO: groupchats*/
     289        struct msn_switchboard *sb;
    243290        struct groupchat *c = imcb_chat_new(ic, who);
    244         return c;
     291
     292        if ((sb = msn_sb_by_handle(ic, who))) {
     293                debug("Converting existing switchboard to %s to a groupchat", who);
     294                return msn_sb_to_chat(sb);
     295        } else {
     296                struct msn_message *m;
     297
     298                /* Create a magic message. This is quite hackish, but who cares? :-P */
     299                m = g_new0(struct msn_message, 1);
     300                m->who = g_strdup(who);
     301                m->text = g_strdup(GROUPCHAT_SWITCHBOARD_MESSAGE);
     302
     303                msn_sb_write_msg(ic, m);
     304
     305                return c;
     306        }
    245307}
    246308
     
    262324static void msn_add_deny(struct im_connection *ic, char *who)
    263325{
     326        struct msn_switchboard *sb;
     327
    264328        msn_buddy_list_add(ic, MSN_BUDDY_BL, who, who, NULL);
     329
     330        /* If there's still a conversation with this person, close it. */
     331        if ((sb = msn_sb_by_handle(ic, who))) {
     332                msn_sb_destroy(sb);
     333        }
    265334}
    266335
  • protocols/msn/msn.h

    r356e2dd r291c49b  
    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"
    3435
    3536#ifdef DEBUG_MSN
     
    5960#define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM"
    6061#define MSNP11_PROD_ID  "PROD0120PW!CCV9@"
    61 #define MSNP_VER        "MSNP21"
     62#define MSNP_VER        "MSNP18"
    6263#define MSNP_BUILD      "14.0.8117.416"
    6364
     
    6768#define MSN_CAP2        0x0000
    6869
    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" \
     70#define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \
     71        "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" \
    7574        "\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" \
    81         "Content-Type: text/plain; charset=UTF-8\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>"
    10475
    10576#define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \
     
    11384        "ID: 1\r\n" \
    11485        "\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"
    11590
    11691#define PROFILE_URL "http://members.msn.com/"
     
    12499} msn_flags_t;
    125100
    126 struct 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 
    148 struct msn_data {
     101struct msn_handler_data {
    149102        int fd, inpa;
    150103        int rxlen;
     
    154107        char *cmd_text;
    155108
     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
     116struct msn_data {
    156117        struct im_connection *ic;
    157118
     119        struct msn_handler_data ns[1];
    158120        msn_flags_t flags;
    159121
     
    164126
    165127        GSList *msgq, *grpq, *soapq;
     128        GSList *switchboards;
     129        int sb_failures;
     130        time_t first_sb_failure;
    166131
    167132        const struct msn_away_state *away_state;
     
    174139        GTree *domaintree;
    175140        int adl_todo;
    176 
    177         gboolean is_http;
    178         struct msn_gw *gw;
     141};
     142
     143struct 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;
    179161};
    180162
     
    223205#define STATUS_FATAL            1
    224206#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). */
    225209
    226210extern int msn_chat_id;
     
    234218   before doing *anything* else. */
    235219extern GSList *msn_connections;
     220extern GSList *msn_switchboards;
    236221
    237222/* ns.c */
    238223int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4);
    239 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port);
    240 void msn_ns_close(struct msn_data *handler);
     224gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port);
     225void msn_ns_close(struct msn_handler_data *handler);
    241226void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error);
    242227void msn_auth_got_contact_list(struct im_connection *ic);
    243228int msn_ns_finish_login(struct im_connection *ic);
    244229int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text);
    245 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts);
    246 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts);
     230void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq);
    247231
    248232/* msn_util.c */
     
    251235int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group);
    252236void msn_buddy_ask(bee_user_t *bu);
    253 void msn_queue_feed(struct msn_data *h, char *bytes, int st);
    254 int msn_handler(struct msn_data *h);
     237char **msn_linesplit(char *line);
     238int msn_handler(struct msn_handler_data *h);
     239void msn_msgq_purge(struct im_connection *ic, GSList **list);
    255240char *msn_p11_challenge(char *challenge);
    256241gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_);
     
    266251const struct msn_status_code *msn_status_by_number(int number);
    267252
    268 /* gw.c */
    269 struct msn_gw *msn_gw_new(struct im_connection *ic);
    270 void msn_gw_free(struct msn_gw *gw);
    271 void msn_gw_open(struct msn_gw *gw);
    272 ssize_t msn_gw_read(struct msn_gw *gw, char **buf);
    273 void msn_gw_write(struct msn_gw *gw, char *buf, size_t len);
     253/* sb.c */
     254int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);;
     255struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session);
     256struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle);
     257struct msn_switchboard *msn_sb_by_chat(struct groupchat *c);
     258struct msn_switchboard *msn_sb_spare(struct im_connection *ic);
     259int msn_sb_sendmessage(struct msn_switchboard *sb, char *text);
     260struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb);
     261void msn_sb_destroy(struct msn_switchboard *sb);
     262gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond);
     263int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m);
     264void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial);
     265void msn_sb_stop_keepalives(struct msn_switchboard *sb);
    274266
    275267#endif //_MSN_H
  • protocols/msn/msn_util.c

    r356e2dd r291c49b  
    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
    5799
    58100        if (!((bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    90132
    91133        *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
    92145
    93146        if (!(bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    172225}
    173226
    174 void 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         }
     227/* *NOT* thread-safe, but that's not a problem for now... */
     228char **msn_linesplit(char *line)
     229{
     230        static char **ret = NULL;
     231        static int size = 3;
     232        int i, n = 0;
     233
     234        if (ret == NULL) {
     235                ret = g_new0(char*, size);
     236        }
     237
     238        for (i = 0; line[i] && line[i] == ' '; i++) {
     239                ;
     240        }
     241        if (line[i]) {
     242                ret[n++] = line + i;
     243                for (i++; line[i]; i++) {
     244                        if (line[i] == ' ') {
     245                                line[i] = 0;
     246                        } else if (line[i] != ' ' && !line[i - 1]) {
     247                                ret[n++] = line + i;
     248                        }
     249
     250                        if (n >= size) {
     251                                ret = g_renew(char*, ret, size += 2);
     252                        }
     253                }
     254        }
     255        ret[n] = NULL;
     256
     257        return(ret);
    185258}
    186259
     
    193266                   1: OK */
    194267
    195 int msn_handler(struct msn_data *h)
    196 {
    197         int st = 1;
     268int msn_handler(struct msn_handler_data *h)
     269{
     270        int st;
     271
     272        h->rxq = g_renew(char, h->rxq, h->rxlen + 1024);
     273        st = read(h->fd, h->rxq + h->rxlen, 1024);
     274        h->rxlen += st;
     275
     276        if (st <= 0) {
     277                return(-1);
     278        }
     279
     280        if (getenv("BITLBEE_DEBUG")) {
     281                write(2, "->C:", 4);
     282                write(2, h->rxq + h->rxlen - st, st);
     283        }
    198284
    199285        while (st) {
     
    207293
    208294                                        cmd_text = g_strndup(h->rxq, i);
    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);
     295                                        cmd = msn_linesplit(cmd_text);
     296                                        for (count = 0; cmd[count]; count++) {
     297                                                ;
     298                                        }
     299                                        st = h->exec_command(h, cmd, count);
    215300                                        g_free(cmd_text);
    216301
     
    235320                        /* If we reached the end of the buffer, there's still an incomplete command there.
    236321                           Return and wait for more data. */
    237                         if (i && i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
     322                        if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
    238323                                break;
    239324                        }
     
    248333
    249334                        msg = g_strndup(h->rxq, h->msglen);
    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);
     335                        cmd = msn_linesplit(h->cmd_text);
     336                        for (count = 0; cmd[count]; count++) {
     337                                ;
     338                        }
     339
     340                        st = h->exec_message(h, msg, h->msglen, cmd, count);
    257341                        g_free(msg);
    258342                        g_free(h->cmd_text);
     
    288372}
    289373
     374void msn_msgq_purge(struct im_connection *ic, GSList **list)
     375{
     376        struct msn_message *m;
     377        GString *ret;
     378        GSList *l;
     379        int n = 0;
     380
     381        l = *list;
     382        if (l == NULL) {
     383                return;
     384        }
     385
     386        m = l->data;
     387        ret = g_string_sized_new(1024);
     388        g_string_printf(ret, "Warning: Cleaning up MSN (switchboard) connection with unsent "
     389                        "messages to %s:", m->who ? m->who : "unknown recipient");
     390
     391        while (l) {
     392                m = l->data;
     393
     394                if (strncmp(m->text, "\r\r\r", 3) != 0) {
     395                        g_string_append_printf(ret, "\n%s", m->text);
     396                        n++;
     397                }
     398
     399                g_free(m->who);
     400                g_free(m->text);
     401                g_free(m);
     402
     403                l = l->next;
     404        }
     405        g_slist_free(*list);
     406        *list = NULL;
     407
     408        if (n > 0) {
     409                imcb_log(ic, "%s", ret->str);
     410        }
     411        g_string_free(ret, TRUE);
     412}
     413
    290414/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
    291415char *msn_p11_challenge(char *challenge)
     
    411535int msn_ns_set_display_name(struct im_connection *ic, const char *value)
    412536{
    413         // TODO, implement this through msn_set_away's method
    414         return 1;
     537        struct msn_data *md = ic->proto_data;
     538        char fn[strlen(value) * 3 + 1];
     539
     540        strcpy(fn, value);
     541        http_encode(fn);
     542
     543        /* Note: We don't actually know if the server accepted the new name,
     544           and won't give proper feedback yet if it doesn't. */
     545        return msn_ns_write(ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn);
    415546}
    416547
  • protocols/msn/ns.c

    r356e2dd r291c49b  
    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);
     37static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);
     38static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);
    3739
    3840static void msn_ns_send_adl_start(struct im_connection *ic);
    3941static void msn_ns_send_adl(struct im_connection *ic);
    40 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd);
    41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action);
    42 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put);
    4342
    4443int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...)
     
    5554
    5655        if (fd < 0) {
    57                 fd = md->fd;
     56                fd = md->ns->fd;
    5857        }
    5958
    6059        if (getenv("BITLBEE_DEBUG")) {
    61                 fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out);
     60                fprintf(stderr, "->NS%d:%s\n", fd, out);
    6261        }
    6362
    6463        len = strlen(out);
    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 
     64        st = write(fd, out, len);
    7365        g_free(out);
    7466        if (st != len) {
     
    8173}
    8274
    83 gboolean 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 
    107 static 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) {
     75gboolean 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) {
    11386                imcb_error(ic, "Could not connect to server");
    11487                imc_logout(ic, TRUE);
     
    11689        }
    11790
    118         g_free(md->rxq);
    119         md->rxlen = 0;
    120         md->rxq = g_new0(char, 1);
     91        return TRUE;
     92}
     93
     94static 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);
    121115
    122116        if (md->uuid == NULL) {
     
    136130
    137131        if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) {
    138                 if (!md->is_http) {
    139                         md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md);
    140                 }
     132                handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler);
    141133                imcb_log(ic, "Connected to server, waiting for reply");
    142134        }
     
    145137}
    146138
    147 void 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;
     139void 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;
    164153}
    165154
    166155static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond)
    167156{
    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) {
     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. */
    181161                imcb_error(ic, "Error while reading from server");
    182162                imc_logout(ic, TRUE);
     163
    183164                return FALSE;
    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 
    197 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts)
    198 {
    199         struct im_connection *ic = md->ic;
     165        } else {
     166                return TRUE;
     167        }
     168}
     169
     170static 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;
    200174
    201175        if (num_parts == 0) {
     
    211185                }
    212186
    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",
     187                return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
    214188                                    ++md->trId, ic->acc->user));
    215189        } else if (strcmp(cmd[0], "CVR") == 0) {
    216190                /* We don't give a damn about the information we just received */
    217                 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
     191                return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
    218192        } else if (strcmp(cmd[0], "XFR") == 0) {
    219193                char *server;
     
    221195
    222196                if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) {
    223                         b_event_remove(md->inpa);
    224                         md->inpa = -1;
     197                        b_event_remove(handler->inpa);
     198                        handler->inpa = -1;
    225199
    226200                        server = strchr(cmd[3], ':');
     
    235209
    236210                        imcb_log(ic, "Transferring to other server");
    237                         return msn_ns_connect(ic, server, port);
     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                        }
    238259                } else {
    239260                        imcb_error(ic, "Syntax error");
     
    269290                }
    270291
    271                 md->msglen = atoi(cmd[3]);
    272 
    273                 if (md->msglen <= 0) {
     292                handler->msglen = atoi(cmd[3]);
     293
     294                if (handler->msglen <= 0) {
    274295                        imcb_error(ic, "Syntax error");
    275296                        imc_logout(ic, TRUE);
    276297                        return(0);
    277298                }
     299        } else if (strcmp(cmd[0], "BLP") == 0) {
     300                msn_ns_send_adl_start(ic);
     301                return msn_ns_finish_login(ic);
    278302        } else if (strcmp(cmd[0], "ADL") == 0) {
    279303                if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) {
     
    281305                        return msn_ns_finish_login(ic);
    282306                } else if (num_parts >= 3) {
    283                         md->msglen = atoi(cmd[2]);
    284                 }
     307                        handler->msglen = atoi(cmd[2]);
     308                }
     309        } else if (strcmp(cmd[0], "PRP") == 0) {
     310                imcb_connected(ic);
    285311        } else if (strcmp(cmd[0], "CHL") == 0) {
    286312                char *resp;
     
    300326                g_free(resp);
    301327                return st;
    302         } else if (strcmp(cmd[0], "QRY") == 0) {
    303                 /* CONGRATULATIONS */
     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                }
    304417        } else if (strcmp(cmd[0], "OUT") == 0) {
    305                 imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown");
    306                 imc_logout(ic, TRUE);
     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);
    307431                return(0);
    308         } else if (strcmp(cmd[0], "GCF") == 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) {
    309485                /* Coming up is cmd[2] bytes of stuff we're supposed to
    310486                   censore. Meh. */
    311                 md->msglen = atoi(cmd[2]);
    312         } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) {
     487                handler->msglen = atoi(cmd[2]);
     488        } else if (strcmp(cmd[0], "UBX") == 0) {
     489                /* Status message. */
    313490                if (num_parts >= 3) {
    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]);
     491                        handler->msglen = atoi(cmd[2]);
    319492                }
    320493        } else if (strcmp(cmd[0], "NOT") == 0) {
     494                /* Some kind of notification, poorly documented but
     495                   apparently used to announce address book changes. */
    321496                if (num_parts >= 2) {
    322                         md->msglen = atoi(cmd[1]);
     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]);
    323502                }
    324503        } else if (strcmp(cmd[0], "QNG") == 0) {
     
    337516                /* Oh yes, errors can have payloads too now. Discard them for now. */
    338517                if (num_parts >= 3) {
    339                         md->msglen = atoi(cmd[2]);
     518                        handler->msglen = atoi(cmd[2]);
    340519                }
    341520        } else {
    342                 imcb_error(ic, "Received unknown command from main server: %s", cmd[0]);
     521                /* debug( "Received unknown command from main server: %s", cmd[0] ); */
    343522        }
    344523
     
    346525}
    347526
    348 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts)
    349 {
    350         struct im_connection *ic = md->ic;
     527static 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;
    351530        char *body;
    352531        int blen = 0;
     
    419598                                }
    420599                        } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) {
    421                                 /* Notification that a message has been read... Ignore it */
     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);
    422652                        } else {
    423653                                debug("Can't handle %s packet from notification server", ct);
     
    426656                        g_free(ct);
    427657                }
     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);
    428670        } else if (strcmp(cmd[0], "ADL") == 0) {
    429671                struct xt_node *adl, *d, *c;
     
    474716                        }
    475717                }
    476         } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) {
    477                 msn_ns_structured_message(md, msg, msglen, cmd);
     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);
    478744        }
    479745
    480746        return 1;
    481 }
    482 
    483 static 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 
    510 cleanup:
    511         g_strfreev(parts);
    512         g_free(action);
    513         g_free(from);
    514         g_free(who);
    515 }
    516 
    517 static 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 
    528 static 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 
    584 cleanup:
    585         xt_free_node(body);
    586747}
    587748
     
    607768void msn_auth_got_contact_list(struct im_connection *ic)
    608769{
     770        struct msn_data *md;
     771
    609772        /* Dead connection? */
    610773        if (g_slist_find(msn_connections, ic) == NULL) {
     
    612775        }
    613776
    614         msn_ns_send_adl_start(ic);
    615         msn_ns_finish_login(ic);
     777        md = ic->proto_data;
     778        msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");
    616779}
    617780
    618781static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data)
    619782{
    620         struct xt_node *adl = data, *d, *c, *s;
     783        struct xt_node *adl = data, *d, *c;
    621784        struct bee_user *bu = value;
    622785        struct msn_buddy_data *bd = bu->data;
     
    647810        c = xt_new_node("c", NULL, NULL);
    648811        xt_add_attr(c, "n", handle);
     812        xt_add_attr(c, "l", l);
    649813        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);
    654814        xt_insert_child(d, c);
    655815
     
    721881
    722882        if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) {
    723                 imcb_connected(ic);
     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                }
    724888        }
    725889
     
    727891}
    728892
    729 // TODO: typing notifications, nudges lol, etc
    730893int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text)
    731894{
    732895        struct msn_data *md = ic->proto_data;
    733         int retval = 0;
    734         char *buf;
     896        int type = 0;
     897        char *buf, *handle;
    735898
    736899        if (strncmp(text, "\r\r\r", 3) == 0) {
     
    740903        }
    741904
    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 }
     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
     928void 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                *msgq = g_slist_remove(*msgq, m);
     947                g_free(m->who);
     948                g_free(m->text);
     949                g_free(m);
     950        }
     951}
  • protocols/msn/soap.c

    r356e2dd r291c49b  
    209209                return;
    210210        }
    211         fprintf(stderr, "\n\x1b[90mSOAP:\n");
    212211
    213212        if (headers) {
     
    226225                xt_free_node(xt);
    227226        }
    228         fprintf(stderr, "\n\x1b[97m\n");
    229227}
    230228
  • protocols/msn/tables.c

    r356e2dd r291c49b  
    7373        { 206, "Domain name missing",                                   0 },
    7474        { 207, "Already logged in",                                     0 },
    75         { 208, "Invalid handle",                                        0 },
     75        { 208, "Invalid handle",                                        STATUS_SB_IM_SPARE },
    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",                                 0 },
    80         { 217, "Person is off-line or non-existent",                    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 },
    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",                                   0 },
     115        { 713, "Calling too rapidly",                                   STATUS_SB_IM_SPARE },
    116116        { 714, "Too many sessions",                                     STATUS_FATAL },
    117117        { 715, "Not expected/Invalid argument/action",                  0 },
Note: See TracChangeset for help on using the changeset viewer.