Changes in / [356e2dd:291c49b]
- Files:
-
- 1 added
- 1 deleted
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
lib/misc.c
r356e2dd r291c49b 719 719 } 720 720 721 /* Make sure we're still inside the string */ 722 if (i >= len) { 723 return(NULL); 724 } 725 721 726 /* Copy the found data */ 722 727 return(g_strndup(ret, text + i - ret)); -
protocols/msn/Makefile
r356e2dd r291c49b 13 13 14 14 # [SH] Program variables 15 objects = msn.o msn_util.o ns.o s oap.o tables.o gw.o15 objects = msn.o msn_util.o ns.o sb.o soap.o tables.o 16 16 17 17 LFLAGS += -r -
protocols/msn/msn.c
r356e2dd r291c49b 30 30 int msn_chat_id; 31 31 GSList *msn_connections; 32 GSList *msn_switchboards; 32 33 33 34 static char *set_eval_display_name(set_t *set, char *value); … … 47 48 48 49 set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc); 50 set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc); 49 51 50 52 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | … … 62 64 63 65 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; 65 71 } 66 72 … … 74 80 md->away_state = msn_away_state_list; 75 81 md->domaintree = g_tree_new(msn_domaintree_cmp); 76 md->fd = -1; 77 md->is_http = TRUE; 82 md->ns->fd = -1; 78 83 79 84 msn_connections = g_slist_prepend(msn_connections, ic); 80 85 81 86 imcb_log(ic, "Connecting"); 82 msn_ns_connect(ic, server,87 msn_ns_connect(ic, md->ns, server, 83 88 set_getint(&ic->acc->set, "port")); 84 89 } … … 91 96 92 97 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); 95 105 msn_soapq_flush(ic, FALSE); 96 106 … … 144 154 { 145 155 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; 146 158 147 159 #ifdef DEBUG 148 160 if (strcmp(who, "raw") == 0) { 149 161 msn_ns_write(ic, -1, "%s\r\n", message); 150 return 0; 151 } 162 } else 152 163 #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 155 179 return(0); 156 180 } … … 174 198 static void msn_set_away(struct im_connection *ic, char *state, char *message) 175 199 { 200 char *uux; 176 201 struct msn_data *md = ic->proto_data; 177 char *nick, *psm, *idle, *statecode, *body, *buf;178 202 179 203 if (state == NULL) { … … 183 207 } 184 208 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); 202 235 } 203 236 … … 225 258 static void msn_chat_msg(struct groupchat *c, char *message, int flags) 226 259 { 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! */ 228 267 } 229 268 230 269 static void msn_chat_invite(struct groupchat *c, char *who, char *message) 231 270 { 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 } 233 276 } 234 277 235 278 static void msn_chat_leave(struct groupchat *c) 236 279 { 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 } 238 285 } 239 286 240 287 static struct groupchat *msn_chat_with(struct im_connection *ic, char *who) 241 288 { 242 /* TODO: groupchats*/289 struct msn_switchboard *sb; 243 290 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 } 245 307 } 246 308 … … 262 324 static void msn_add_deny(struct im_connection *ic, char *who) 263 325 { 326 struct msn_switchboard *sb; 327 264 328 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 } 265 334 } 266 335 -
protocols/msn/msn.h
r356e2dd r291c49b 32 32 #define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r" 33 33 #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" 34 35 35 36 #ifdef DEBUG_MSN … … 59 60 #define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM" 60 61 #define MSNP11_PROD_ID "PROD0120PW!CCV9@" 61 #define MSNP_VER "MSNP 21"62 #define MSNP_VER "MSNP18" 62 63 #define MSNP_BUILD "14.0.8117.416" 63 64 … … 67 68 #define MSN_CAP2 0x0000 68 69 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" \ 75 74 "\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>"104 75 105 76 #define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \ … … 113 84 "ID: 1\r\n" \ 114 85 "\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" 115 90 116 91 #define PROFILE_URL "http://members.msn.com/" … … 124 99 } msn_flags_t; 125 100 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 { 101 struct msn_handler_data { 149 102 int fd, inpa; 150 103 int rxlen; … … 154 107 char *cmd_text; 155 108 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 { 156 117 struct im_connection *ic; 157 118 119 struct msn_handler_data ns[1]; 158 120 msn_flags_t flags; 159 121 … … 164 126 165 127 GSList *msgq, *grpq, *soapq; 128 GSList *switchboards; 129 int sb_failures; 130 time_t first_sb_failure; 166 131 167 132 const struct msn_away_state *away_state; … … 174 139 GTree *domaintree; 175 140 int adl_todo; 176 177 gboolean is_http; 178 struct msn_gw *gw; 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; 179 161 }; 180 162 … … 223 205 #define STATUS_FATAL 1 224 206 #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). */ 225 209 226 210 extern int msn_chat_id; … … 234 218 before doing *anything* else. */ 235 219 extern GSList *msn_connections; 220 extern GSList *msn_switchboards; 236 221 237 222 /* ns.c */ 238 223 int 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);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); 241 226 void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error); 242 227 void msn_auth_got_contact_list(struct im_connection *ic); 243 228 int msn_ns_finish_login(struct im_connection *ic); 244 229 int 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); 230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq); 247 231 248 232 /* msn_util.c */ … … 251 235 int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group); 252 236 void 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); 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); 255 240 char *msn_p11_challenge(char *challenge); 256 241 gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_); … … 266 251 const struct msn_status_code *msn_status_by_number(int number); 267 252 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 */ 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); 274 266 275 267 #endif //_MSN_H -
protocols/msn/msn_util.c
r356e2dd r291c49b 55 55 56 56 *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 57 99 58 100 if (!((bu = bee_user_by_handle(ic->bee, ic, who)) || … … 90 132 91 133 *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 92 145 93 146 if (!(bu = bee_user_by_handle(ic->bee, ic, who)) || … … 172 225 } 173 226 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... */ 228 char **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); 185 258 } 186 259 … … 193 266 1: OK */ 194 267 195 int msn_handler(struct msn_data *h) 196 { 197 int st = 1; 268 int 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 } 198 284 199 285 while (st) { … … 207 293 208 294 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); 215 300 g_free(cmd_text); 216 301 … … 235 320 /* If we reached the end of the buffer, there's still an incomplete command there. 236 321 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') { 238 323 break; 239 324 } … … 248 333 249 334 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); 257 341 g_free(msg); 258 342 g_free(h->cmd_text); … … 288 372 } 289 373 374 void 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 290 414 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 291 415 char *msn_p11_challenge(char *challenge) … … 411 535 int msn_ns_set_display_name(struct im_connection *ic, const char *value) 412 536 { 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); 415 546 } 416 547 -
protocols/msn/ns.c
r356e2dd r291c49b 35 35 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond); 36 36 static 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); 37 39 38 40 static void msn_ns_send_adl_start(struct im_connection *ic); 39 41 static 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);43 42 44 43 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) … … 55 54 56 55 if (fd < 0) { 57 fd = md-> fd;56 fd = md->ns->fd; 58 57 } 59 58 60 59 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); 62 61 } 63 62 64 63 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); 73 65 g_free(out); 74 66 if (st != len) { … … 81 73 } 82 74 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) { 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) { 113 86 imcb_error(ic, "Could not connect to server"); 114 87 imc_logout(ic, TRUE); … … 116 89 } 117 90 118 g_free(md->rxq); 119 md->rxlen = 0; 120 md->rxq = g_new0(char, 1); 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); 121 115 122 116 if (md->uuid == NULL) { … … 136 130 137 131 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); 141 133 imcb_log(ic, "Connected to server, waiting for reply"); 142 134 } … … 145 137 } 146 138 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; 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; 164 153 } 165 154 166 155 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 167 156 { 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. */ 181 161 imcb_error(ic, "Error while reading from server"); 182 162 imc_logout(ic, TRUE); 163 183 164 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 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; 200 174 201 175 if (num_parts == 0) { … … 211 185 } 212 186 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", 214 188 ++md->trId, ic->acc->user)); 215 189 } else if (strcmp(cmd[0], "CVR") == 0) { 216 190 /* 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); 218 192 } else if (strcmp(cmd[0], "XFR") == 0) { 219 193 char *server; … … 221 195 222 196 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; 225 199 226 200 server = strchr(cmd[3], ':'); … … 235 209 236 210 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 } 238 259 } else { 239 260 imcb_error(ic, "Syntax error"); … … 269 290 } 270 291 271 md->msglen = atoi(cmd[3]);272 273 if ( md->msglen <= 0) {292 handler->msglen = atoi(cmd[3]); 293 294 if (handler->msglen <= 0) { 274 295 imcb_error(ic, "Syntax error"); 275 296 imc_logout(ic, TRUE); 276 297 return(0); 277 298 } 299 } else if (strcmp(cmd[0], "BLP") == 0) { 300 msn_ns_send_adl_start(ic); 301 return msn_ns_finish_login(ic); 278 302 } else if (strcmp(cmd[0], "ADL") == 0) { 279 303 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { … … 281 305 return msn_ns_finish_login(ic); 282 306 } 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); 285 311 } else if (strcmp(cmd[0], "CHL") == 0) { 286 312 char *resp; … … 300 326 g_free(resp); 301 327 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 } 304 417 } 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); 307 431 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) { 309 485 /* Coming up is cmd[2] bytes of stuff we're supposed to 310 486 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. */ 313 490 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]); 319 492 } 320 493 } else if (strcmp(cmd[0], "NOT") == 0) { 494 /* Some kind of notification, poorly documented but 495 apparently used to announce address book changes. */ 321 496 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]); 323 502 } 324 503 } else if (strcmp(cmd[0], "QNG") == 0) { … … 337 516 /* Oh yes, errors can have payloads too now. Discard them for now. */ 338 517 if (num_parts >= 3) { 339 md->msglen = atoi(cmd[2]);518 handler->msglen = atoi(cmd[2]); 340 519 } 341 520 } 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] ); */ 343 522 } 344 523 … … 346 525 } 347 526 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;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; 351 530 char *body; 352 531 int blen = 0; … … 419 598 } 420 599 } 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); 422 652 } else { 423 653 debug("Can't handle %s packet from notification server", ct); … … 426 656 g_free(ct); 427 657 } 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); 428 670 } else if (strcmp(cmd[0], "ADL") == 0) { 429 671 struct xt_node *adl, *d, *c; … … 474 716 } 475 717 } 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); 478 744 } 479 745 480 746 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);586 747 } 587 748 … … 607 768 void msn_auth_got_contact_list(struct im_connection *ic) 608 769 { 770 struct msn_data *md; 771 609 772 /* Dead connection? */ 610 773 if (g_slist_find(msn_connections, ic) == NULL) { … … 612 775 } 613 776 614 m sn_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"); 616 779 } 617 780 618 781 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 619 782 { 620 struct xt_node *adl = data, *d, *c , *s;783 struct xt_node *adl = data, *d, *c; 621 784 struct bee_user *bu = value; 622 785 struct msn_buddy_data *bd = bu->data; … … 647 810 c = xt_new_node("c", NULL, NULL); 648 811 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l); 649 813 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);654 814 xt_insert_child(d, c); 655 815 … … 721 881 722 882 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 } 724 888 } 725 889 … … 727 891 } 728 892 729 // TODO: typing notifications, nudges lol, etc730 893 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 731 894 { 732 895 struct msn_data *md = ic->proto_data; 733 int retval= 0;734 char *buf ;896 int type = 0; 897 char *buf, *handle; 735 898 736 899 if (strncmp(text, "\r\r\r", 3) == 0) { … … 740 903 } 741 904 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 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 *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 209 209 return; 210 210 } 211 fprintf(stderr, "\n\x1b[90mSOAP:\n");212 211 213 212 if (headers) { … … 226 225 xt_free_node(xt); 227 226 } 228 fprintf(stderr, "\n\x1b[97m\n");229 227 } 230 228 -
protocols/msn/tables.c
r356e2dd r291c49b 73 73 { 206, "Domain name missing", 0 }, 74 74 { 207, "Already logged in", 0 }, 75 { 208, "Invalid handle", 0},75 { 208, "Invalid handle", STATUS_SB_IM_SPARE }, 76 76 { 209, "Forbidden nickname", 0 }, 77 77 { 210, "Buddy list too long", 0 }, 78 78 { 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 }, 81 81 { 218, "Already in that mode", 0 }, 82 82 { 219, "Handle is already in opposite list", 0 }, … … 113 113 { 711, "Write is blocking", STATUS_FATAL }, 114 114 { 712, "Session is overloaded", STATUS_FATAL }, 115 { 713, "Calling too rapidly", 0},115 { 713, "Calling too rapidly", STATUS_SB_IM_SPARE }, 116 116 { 714, "Too many sessions", STATUS_FATAL }, 117 117 { 715, "Not expected/Invalid argument/action", 0 },
Note: See TracChangeset
for help on using the changeset viewer.