libgaim/protocols/msn/oim.c

branch
cpw.khc.msnp14
changeset 20472
6a6d2ef151e6
child 20473
91e1b3a49d10
equal deleted inserted replaced
13912:463b4fa9f067 20472:6a6d2ef151e6
1 /**
2 * @file oim.c
3 * get and send MSN offline Instant Message via SOAP request
4 * Author
5 * MaYuan<mayuan2006@gmail.com>
6 * gaim
7 *
8 * Gaim is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26 #include "msn.h"
27 #include "soap.h"
28 #include "oim.h"
29 #include "msn-utils.h"
30
31 /*Local Function Prototype*/
32 static void msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid);
33 void msn_oim_retrieve_connect_init(MsnSoapConn *soapconn);
34 void msn_oim_send_connect_init(MsnSoapConn *soapconn);
35 void msn_oim_free_send_req(MsnOimSendReq *req);
36
37 /*new a OIM object*/
38 MsnOim *
39 msn_oim_new(MsnSession *session)
40 {
41 MsnOim *oim;
42
43 oim = g_new0(MsnOim, 1);
44 oim->session = session;
45 oim->retrieveconn = msn_soap_new(session,oim,1);
46
47 oim->oim_list = NULL;
48 oim->sendconn = msn_soap_new(session,oim,1);
49 oim->run_id = rand_guid();
50 oim->challenge = NULL;
51 oim->send_queue = g_queue_new();
52 oim->send_seq = 1;
53 return oim;
54 }
55
56 /*destroy the oim object*/
57 void
58 msn_oim_destroy(MsnOim *oim)
59 {
60 MsnOimSendReq *request;
61
62 gaim_debug_info("OIM","destroy the OIM \n");
63 msn_soap_destroy(oim->retrieveconn);
64 msn_soap_destroy(oim->sendconn);
65 g_free(oim->run_id);
66 g_free(oim->challenge);
67
68 while((request = g_queue_pop_head(oim->send_queue)) != NULL){
69 msn_oim_free_send_req(request);
70 }
71 g_queue_free(oim->send_queue);
72
73 g_free(oim);
74 }
75
76 MsnOimSendReq *
77 msn_oim_new_send_req(char *from_member,
78 char*friendname,char* to_member,
79 gint send_seq,
80 char *msg)
81 {
82 MsnOimSendReq *request;
83
84 request = g_new0(MsnOimSendReq, 1);
85 request->from_member =g_strdup(from_member);
86 request->friendname = g_strdup(friendname);
87 request->to_member = g_strdup(to_member);
88 request->send_seq = send_seq;
89 request->oim_msg = g_strdup(msg);
90 return request;
91 }
92
93 void
94 msn_oim_free_send_req(MsnOimSendReq *req)
95 {
96 g_return_if_fail(req != NULL);
97
98 g_free(req->from_member);
99 g_free(req->friendname);
100 g_free(req->to_member);
101 g_free(req->oim_msg);
102
103 g_free(req);
104 }
105
106 /****************************************
107 * OIM send SOAP request
108 * **************************************/
109 /*encode the message to OIM Message Format*/
110 char *
111 msn_oim_msg_to_str(MsnOim *oim,char *body)
112 {
113 char *oim_body,*oim_base64;
114
115 gaim_debug_info("MaYuan","encode OIM Message...\n");
116 oim_base64 = gaim_base64_encode((const guchar *)body, strlen(body));
117 gaim_debug_info("MaYuan","encoded base64 body:{%s}\n",oim_base64);
118 oim_body = g_strdup_printf(MSN_OIM_MSG_TEMPLATE,
119 oim->run_id,oim->send_seq,oim_base64);
120
121 return oim_body;
122 }
123
124 /*oim SOAP server login error*/
125 static void
126 msn_oim_send_error_cb(GaimSslConnection *gsc, GaimSslErrorType error, void *data)
127 {
128 MsnSoapConn *soapconn = data;
129 MsnSession *session;
130
131 session = soapconn->session;
132 g_return_if_fail(session != NULL);
133
134 msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server"));
135 }
136
137 /*msn oim SOAP server connect process*/
138 static void
139 msn_oim_send_connect_cb(gpointer data, GaimSslConnection *gsc,
140 GaimInputCondition cond)
141 {
142 MsnSoapConn *soapconn = data;
143 MsnSession * session;
144 MsnOim *oim;
145
146 oim = soapconn->parent;
147 g_return_if_fail(oim != NULL);
148
149 session = oim->session;
150 g_return_if_fail(session != NULL);
151 }
152
153 /*
154 * Process the send return SOAP string
155 * If got SOAP Fault,get the lock key,and resend it.
156 */
157 void
158 msn_oim_send_process(MsnOim *oim,char *body,int len)
159 {
160 xmlnode *responseNode,*bodyNode;
161 xmlnode *faultNode,*faultCodeNode,*faultstringNode;
162 xmlnode *detailNode,*challengeNode;
163 char *faultCodeStr,*faultstring;
164 char *challenge;
165
166 responseNode = xmlnode_from_str(body,len);
167 g_return_if_fail(responseNode != NULL);
168 bodyNode = xmlnode_get_child(responseNode,"Body");
169 faultNode = xmlnode_get_child(bodyNode,"Fault");
170 if(faultNode == NULL){
171 /*Send OK! return*/
172 MsnOimSendReq *request;
173
174 gaim_debug_info("MaYuan","send OIM OK!");
175 xmlnode_free(responseNode);
176 request = g_queue_pop_head(oim->send_queue);
177 msn_oim_free_send_req(request);
178 /*send next buffered Offline Message*/
179 msn_soap_post(oim->sendconn,NULL,msn_oim_send_connect_init);
180 return;
181 }
182 /*get the challenge,and repost it*/
183 faultCodeNode = xmlnode_get_child(faultNode,"faultcode");
184 if(faultCodeNode == NULL){
185 gaim_debug_info("MaYuan","faultcode Node is NULL\n");
186 goto oim_send_process_fail;
187 }
188 faultCodeStr = xmlnode_get_data(faultCodeNode);
189 gaim_debug_info("MaYuan","fault code:{%s}\n",faultCodeStr);
190
191 if(strcmp(faultCodeStr,"q0:AuthenticationFailed")){
192 /*other Fault Reason?*/
193 goto oim_send_process_fail;
194 }
195
196 faultstringNode = xmlnode_get_child(faultNode,"faultstring");
197 faultstring = xmlnode_get_data(faultstringNode);
198 gaim_debug_info("MaYuan","fault string :{%s}\n",faultstring);
199
200 /* lock key fault reason,
201 * compute the challenge and resend it
202 */
203 detailNode = xmlnode_get_child(faultNode, "detail");
204 if(detailNode == NULL){
205 goto oim_send_process_fail;
206 }
207 challengeNode = xmlnode_get_child(detailNode,"LockKeyChallenge");
208
209 g_free(oim->challenge);
210 oim->challenge = xmlnode_get_data(challengeNode);
211 gaim_debug_info("MaYuan","lockkey:{%s}\n",oim->challenge);
212
213 /*repost the send*/
214 gaim_debug_info("MaYuan","prepare to repost the send...\n");
215 msn_oim_send_msg(oim);
216
217 oim_send_process_fail:
218 xmlnode_free(responseNode);
219 return ;
220 }
221
222 static void
223 msn_oim_send_read_cb(gpointer data, GaimSslConnection *gsc,
224 GaimInputCondition cond)
225 {
226 MsnSoapConn * soapconn = data;
227 MsnSession *session = soapconn->session;
228 MsnOim * oim;
229
230 g_return_if_fail(session != NULL);
231 oim = soapconn->session->oim;
232 g_return_if_fail(oim != NULL);
233
234 gaim_debug_info("MaYuan","read buffer:{%s}\n",soapconn->body);
235 msn_oim_send_process(oim,soapconn->body,soapconn->body_len);
236 }
237
238 static void
239 msn_oim_send_written_cb(gpointer data, gint source, GaimInputCondition cond)
240 {
241 MsnSoapConn * soapconn = data;
242
243 soapconn->read_cb = msn_oim_send_read_cb;
244 // msn_soap_read_cb(data,source,cond);
245 }
246
247 void
248 msn_oim_prep_send_msg_info(MsnOim *oim,
249 char *membername,char*friendname,char *tomember,
250 char * msg)
251 {
252 MsnOimSendReq *request;
253
254 request = msn_oim_new_send_req(membername,friendname,tomember,oim->send_seq,msg);
255 g_queue_push_tail(oim->send_queue,request);
256 }
257
258 /*post send single message request to oim server*/
259 void
260 msn_oim_send_msg(MsnOim *oim)
261 {
262 MsnSoapReq *soap_request;
263 MsnOimSendReq *oim_request;
264 char *soap_body,*mspauth;
265 char *msg_body;
266 char buf[33];
267
268 g_return_if_fail(oim != NULL);
269 oim_request = g_queue_pop_head(oim->send_queue);
270 g_return_if_fail(oim_request != NULL);
271
272 gaim_debug_info("MaYuan","send single OIM Message\n");
273 mspauth = g_strdup_printf("t=%s&amp;p=%s",
274 oim->session->passport_info.t,
275 oim->session->passport_info.p
276 );
277 g_queue_push_head(oim->send_queue,oim_request);
278
279 /* if we got the challenge lock key, we compute it
280 * else we go for the SOAP fault and resend it.
281 */
282 if(oim->challenge != NULL){
283 msn_handle_chl(oim->challenge, buf);
284 }else{
285 gaim_debug_info("MaYuan","no lock key challenge,wait for SOAP Fault and Resend\n");
286 buf[0]='\0';
287 }
288 gaim_debug_info("MaYuan","get the lock key challenge {%s}\n",buf);
289
290 msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg);
291 soap_body = g_strdup_printf(MSN_OIM_SEND_TEMPLATE,
292 oim_request->from_member,
293 oim_request->friendname,
294 oim_request->to_member,
295 mspauth,
296 MSNP13_WLM_PRODUCT_ID,
297 buf,
298 oim_request->send_seq,
299 msg_body
300 );
301 soap_request = msn_soap_request_new(MSN_OIM_SEND_HOST,
302 MSN_OIM_SEND_URL,MSN_OIM_SEND_SOAP_ACTION,
303 soap_body,
304 msn_oim_send_read_cb,
305 msn_oim_send_written_cb);
306 g_free(mspauth);
307 g_free(msg_body);
308 g_free(soap_body);
309
310 /*increase the offline Sequence control*/
311 if(oim->challenge != NULL){
312 oim->send_seq++;
313 }
314 msn_soap_post(oim->sendconn,soap_request,msn_oim_send_connect_init);
315 }
316
317 /****************************************
318 * OIM delete SOAP request
319 * **************************************/
320 static void
321 msn_oim_delete_read_cb(gpointer data, GaimSslConnection *gsc,
322 GaimInputCondition cond)
323 {
324 MsnSoapConn * soapconn = data;
325 MsnOim * oim = soapconn->session->oim;
326
327 gaim_debug_info("MaYuan","OIM delete read buffer:{%s}\n",soapconn->body);
328
329 msn_soap_free_read_buf(soapconn);
330 /*get next single Offline Message*/
331 msn_soap_post(soapconn,NULL,msn_oim_retrieve_connect_init);
332 }
333
334 static void
335 msn_oim_delete_written_cb(gpointer data, gint source, GaimInputCondition cond)
336 {
337 MsnSoapConn * soapconn = data;
338
339 soapconn->read_cb = msn_oim_delete_read_cb;
340 }
341
342 /*Post to get the Offline Instant Message*/
343 static void
344 msn_oim_post_delete_msg(MsnOim *oim,const char *msgid)
345 {
346 MsnSoapReq *soap_request;
347 const char *soap_body,*t,*p;
348
349 g_return_if_fail(oim != NULL);
350 g_return_if_fail(msgid != NULL);
351
352 gaim_debug_info("MaYuan","Delete single OIM Message {%s}\n",msgid);
353 t = oim->session->passport_info.t;
354 p = oim->session->passport_info.p;
355
356 soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE,
357 t,
358 p,
359 msgid
360 );
361 soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST,
362 MSN_OIM_RETRIEVE_URL,MSN_OIM_DEL_SOAP_ACTION,
363 soap_body,
364 msn_oim_delete_read_cb,
365 msn_oim_delete_written_cb);
366 msn_soap_post(oim->retrieveconn,soap_request,msn_oim_retrieve_connect_init);
367 }
368
369 /****************************************
370 * OIM get SOAP request
371 * **************************************/
372 /*oim SOAP server login error*/
373 static void
374 msn_oim_get_error_cb(GaimSslConnection *gsc, GaimSslErrorType error, void *data)
375 {
376 MsnSoapConn *soapconn = data;
377 MsnSession *session;
378
379 session = soapconn->session;
380 g_return_if_fail(session != NULL);
381 msn_soap_clean_unhandled_request(soapconn);
382
383 // msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server"));
384 }
385
386 /*msn oim SOAP server connect process*/
387 static void
388 msn_oim_get_connect_cb(gpointer data, GaimSslConnection *gsc,
389 GaimInputCondition cond)
390 {
391 MsnSoapConn *soapconn = data;
392 MsnSession * session;
393 MsnOim *oim;
394
395 oim = soapconn->parent;
396 g_return_if_fail(oim != NULL);
397
398 session = oim->session;
399 g_return_if_fail(session != NULL);
400
401 gaim_debug_info("MaYuan","oim get SOAP Server connected!\n");
402 }
403
404 /*Post the Offline Instant Message to User Conversation*/
405 void
406 msn_oim_report_to_user(MsnOim *oim,char *msg_str)
407 {
408 MsnMessage *message;
409 char *date,*from,*decode_msg;
410 gsize body_len;
411 char **tokens;
412 char *start,*end;
413 int has_nick = 0;
414 char *passport_str,*passport;
415 char *msg_id;
416
417 message = msn_message_new(MSN_MSG_UNKNOWN);
418
419 msn_message_parse_payload(message,msg_str,strlen(msg_str),
420 MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);
421 gaim_debug_info("MaYuan","oim body:{%s}\n",message->body);
422 decode_msg = gaim_base64_decode(message->body,&body_len);
423 date = (char *)g_hash_table_lookup(message->attr_table, "Date");
424 from = (char *)g_hash_table_lookup(message->attr_table, "From");
425 if(strstr(from," ")){
426 has_nick = 1;
427 }
428 if(has_nick){
429 tokens = g_strsplit(from , " " , 2);
430 passport_str = g_strdup(tokens[1]);
431 gaim_debug_info("MaYuan","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n",
432 date,tokens[0],tokens[1],passport_str);
433 g_strfreev(tokens);
434 }else{
435 passport_str = g_strdup(from);
436 gaim_debug_info("MaYuan","oim Date:{%s},passport{%s}\n",
437 date,passport_str);
438 }
439 start = strstr(passport_str,"<");
440 start += 1;
441 end = strstr(passport_str,">");
442 passport = g_strndup(start,end - start);
443 g_free(passport_str);
444 gaim_debug_info("MaYuan","oim Date:{%s},passport{%s}\n",date,passport);
445
446 msn_session_report_user(oim->session,passport,decode_msg,GAIM_MESSAGE_SYSTEM);
447
448 /*Now get the oim message ID from the oim_list.
449 * and append to read list to prepare for deleting the Offline Message when sign out
450 */
451 if(oim->oim_list != NULL){
452 msg_id = oim->oim_list->data;
453 msn_oim_post_delete_msg(oim,msg_id);
454 oim->oim_list = g_list_remove(oim->oim_list, oim->oim_list->data);
455 g_free(msg_id);
456 }
457
458 g_free(passport);
459 }
460
461 /* Parse the XML data,
462 * prepare to report the OIM to user
463 */
464 void
465 msn_oim_get_process(MsnOim *oim,char *oim_msg)
466 {
467 xmlnode *oimNode,*bodyNode,*responseNode,*msgNode;
468 char *msg_data,*msg_str;
469
470 oimNode = xmlnode_from_str(oim_msg, strlen(oim_msg));
471 bodyNode = xmlnode_get_child(oimNode,"Body");
472 responseNode = xmlnode_get_child(bodyNode,"GetMessageResponse");
473 msgNode = xmlnode_get_child(responseNode,"GetMessageResult");
474 msg_data = xmlnode_get_data(msgNode);
475 msg_str = g_strdup(msg_data);
476 g_free(msg_data);
477 gaim_debug_info("OIM","msg:{%s}\n",msg_str);
478 msn_oim_report_to_user(oim,msg_str);
479
480 g_free(msg_str);
481 }
482
483 static void
484 msn_oim_get_read_cb(gpointer data, GaimSslConnection *gsc,
485 GaimInputCondition cond)
486 {
487 MsnSoapConn * soapconn = data;
488 MsnOim * oim = soapconn->session->oim;
489
490 gaim_debug_info("MaYuan","OIM get read buffer:{%s}\n",soapconn->body);
491
492 /*we need to process the read message!*/
493 msn_oim_get_process(oim,soapconn->body);
494 msn_soap_free_read_buf(soapconn);
495
496 /*get next single Offline Message*/
497 msn_soap_post(soapconn,NULL,msn_oim_retrieve_connect_init);
498 }
499
500 static void
501 msn_oim_get_written_cb(gpointer data, gint source, GaimInputCondition cond)
502 {
503 MsnSoapConn * soapconn = data;
504
505 soapconn->read_cb = msn_oim_get_read_cb;
506 // msn_soap_read_cb(data,source,cond);
507 }
508
509 /* parse the oim XML data
510 * and post it to the soap server to get the Offline Message
511 * */
512 void
513 msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg)
514 {
515 xmlnode *mdNode,*mNode,*ENode,*INode,*rtNode,*nNode;
516 char *passport,*rTime,*msgid,*nickname;
517
518 mdNode = xmlnode_from_str(xmlmsg, strlen(xmlmsg));
519 for(mNode = xmlnode_get_child(mdNode, "M"); mNode;
520 mNode = xmlnode_get_next_twin(mNode)){
521 /*email Node*/
522 ENode = xmlnode_get_child(mNode,"E");
523 passport = xmlnode_get_data(ENode);
524 /*Index */
525 INode = xmlnode_get_child(mNode,"I");
526 msgid = xmlnode_get_data(INode);
527 /*Nickname*/
528 nNode = xmlnode_get_child(mNode,"N");
529 nickname = xmlnode_get_data(nNode);
530 /*receive time*/
531 rtNode = xmlnode_get_child(mNode,"RT");
532 if(rtNode != NULL)
533 rTime = xmlnode_get_data(rtNode);
534 /* gaim_debug_info("MaYuan","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime);*/
535
536 oim->oim_list = g_list_append(oim->oim_list,msgid);
537 msn_oim_post_single_get_msg(oim,msgid);
538 g_free(passport);
539 // g_free(msgid);
540 g_free(rTime);
541 g_free(nickname);
542 }
543 }
544
545 /*Post to get the Offline Instant Message*/
546 static void
547 msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid)
548 {
549 MsnSoapReq *soap_request;
550 const char *soap_body,*t,*p;
551
552 gaim_debug_info("MaYuan","Get single OIM Message\n");
553 t = oim->session->passport_info.t;
554 p = oim->session->passport_info.p;
555
556 soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE,
557 t,
558 p,
559 msgid
560 );
561 soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST,
562 MSN_OIM_RETRIEVE_URL,MSN_OIM_GET_SOAP_ACTION,
563 soap_body,
564 msn_oim_get_read_cb,
565 msn_oim_get_written_cb);
566 msn_soap_post(oim->retrieveconn,soap_request,msn_oim_retrieve_connect_init);
567 }
568
569 /*msn oim retrieve server connect init */
570 void
571 msn_oim_retrieve_connect_init(MsnSoapConn *soapconn)
572 {
573 gaim_debug_info("MaYuan","msn_oim_connect...\n");
574 msn_soap_init(soapconn,MSN_OIM_RETRIEVE_HOST,1,
575 msn_oim_get_connect_cb,
576 msn_oim_get_error_cb);
577 }
578
579 /*Msn OIM Send Server Connect Init Function*/
580 void msn_oim_send_connect_init(MsnSoapConn *sendconn)
581 {
582 gaim_debug_info("MaYuan","msn oim send connect init...\n");
583 msn_soap_init(sendconn,MSN_OIM_SEND_HOST,1,
584 msn_oim_send_connect_cb,
585 msn_oim_send_error_cb);
586 }
587
588 /*endof oim.c*/

mercurial