Mercurial > pidgin.yaz
annotate src/protocols/sametime/meanwhile/srvc_ft.c @ 10977:2ce8ec01a064
[gaim-migrate @ 12803]
adding sametime support to the build
committer: Tailor Script <tailor@pidgin.im>
author | Christopher O'Brien <siege@pidgin.im> |
---|---|
date | Tue, 07 Jun 2005 02:52:39 +0000 |
parents | 3ef77720e577 |
children | 0110fc7c6a8a |
rev | line source |
---|---|
10969 | 1 |
2 /* | |
3 Meanwhile - Unofficial Lotus Sametime Community Client Library | |
4 Copyright (C) 2004 Christopher (siege) O'Brien | |
5 | |
6 This library is free software; you can redistribute it and/or | |
7 modify it under the terms of the GNU Library General Public | |
8 License as published by the Free Software Foundation; either | |
9 version 2 of the License, or (at your option) any later version. | |
10 | |
11 This library is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 Library General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU Library General Public | |
17 License along with this library; if not, write to the Free | |
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 */ | |
20 | |
21 | |
22 #include <glib/glist.h> | |
23 | |
24 #include "mw_channel.h" | |
25 #include "mw_common.h" | |
26 #include "mw_debug.h" | |
27 #include "mw_error.h" | |
28 #include "mw_message.h" | |
29 #include "mw_service.h" | |
30 #include "mw_session.h" | |
31 #include "mw_srvc_ft.h" | |
32 #include "mw_util.h" | |
33 | |
34 | |
35 #define PROTOCOL_TYPE 0x00000000 | |
36 #define PROTOCOL_VER 0x00000001 | |
37 | |
38 | |
39 /** send-on-channel type: FT transfer data */ | |
40 #define msg_TRANSFER 0x0001 | |
41 | |
42 | |
43 /** ack received transfer data */ | |
44 #define msg_RECEIVED 0x0002 | |
45 | |
46 | |
47 struct mwServiceFileTransfer { | |
48 struct mwService service; | |
49 | |
50 struct mwFileTransferHandler *handler; | |
51 GList *transfers; | |
52 }; | |
53 | |
54 | |
55 struct mwFileTransfer { | |
56 struct mwServiceFileTransfer *service; | |
57 | |
58 struct mwChannel *channel; | |
59 struct mwIdBlock who; | |
60 | |
61 enum mwFileTransferState state; | |
62 | |
63 char *filename; | |
64 char *message; | |
65 | |
66 guint32 size; | |
67 guint32 remaining; | |
68 | |
69 struct mw_datum client_data; | |
70 }; | |
71 | |
72 | |
73 /** momentarily places a mwLoginInfo into a mwIdBlock */ | |
74 static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) { | |
75 to->user = from->user_id; | |
76 to->community = from->community; | |
77 } | |
78 | |
79 | |
80 static const char *ft_state_str(enum mwFileTransferState state) { | |
81 switch(state) { | |
82 case mwFileTransfer_NEW: | |
83 return "new"; | |
84 | |
85 case mwFileTransfer_PENDING: | |
86 return "pending"; | |
87 | |
88 case mwFileTransfer_OPEN: | |
89 return "open"; | |
90 | |
91 case mwFileTransfer_CANCEL_LOCAL: | |
92 return "cancelled locally"; | |
93 | |
94 case mwFileTransfer_CANCEL_REMOTE: | |
95 return "cancelled remotely"; | |
96 | |
97 case mwFileTransfer_DONE: | |
98 return "done"; | |
99 | |
100 case mwFileTransfer_ERROR: | |
101 return "error"; | |
102 | |
103 case mwFileTransfer_UNKNOWN: | |
104 default: | |
105 return "UNKNOWN"; | |
106 } | |
107 } | |
108 | |
109 | |
110 static void ft_state(struct mwFileTransfer *ft, | |
111 enum mwFileTransferState state) { | |
112 | |
113 g_return_if_fail(ft != NULL); | |
114 | |
115 if(ft->state == state) return; | |
116 | |
117 g_info("setting ft (%s, %s) state: %s", | |
118 NSTR(ft->who.user), NSTR(ft->who.community), | |
119 ft_state_str(state)); | |
120 | |
121 ft->state = state; | |
122 } | |
123 | |
124 | |
125 static void recv_channelCreate(struct mwServiceFileTransfer *srvc, | |
126 struct mwChannel *chan, | |
127 struct mwMsgChannelCreate *msg) { | |
128 | |
129 struct mwFileTransferHandler *handler; | |
130 struct mwGetBuffer *b; | |
131 | |
132 char *fnm, *txt; | |
133 guint32 size, junk; | |
134 gboolean b_err; | |
135 | |
136 g_return_if_fail(srvc->handler != NULL); | |
137 handler = srvc->handler; | |
138 | |
139 b = mwGetBuffer_wrap(&msg->addtl); | |
140 | |
141 guint32_get(b, &junk); /* unknown */ | |
142 mwString_get(b, &fnm); /* offered filename */ | |
143 mwString_get(b, &txt); /* offering message */ | |
144 guint32_get(b, &size); /* size of offered file */ | |
145 guint32_get(b, &junk); /* unknown */ | |
146 /* and we just skip an unknown guint16 at the end */ | |
147 | |
148 b_err = mwGetBuffer_error(b); | |
149 mwGetBuffer_free(b); | |
150 | |
151 if(b_err) { | |
152 g_warning("bad/malformed addtl in File Transfer service"); | |
153 mwChannel_destroy(chan, ERR_FAILURE, NULL); | |
154 | |
155 } else { | |
156 struct mwIdBlock idb; | |
157 struct mwFileTransfer *ft; | |
158 | |
159 login_into_id(&idb, mwChannel_getUser(chan)); | |
160 ft = mwFileTransfer_new(srvc, &idb, txt, fnm, size); | |
161 ft->channel = chan; | |
162 ft_state(ft, mwFileTransfer_PENDING); | |
163 | |
164 mwChannel_setServiceData(chan, ft, NULL); | |
165 | |
166 if(handler->ft_offered) | |
167 handler->ft_offered(ft); | |
168 } | |
169 | |
170 g_free(fnm); | |
171 g_free(txt); | |
172 } | |
173 | |
174 | |
175 static void recv_channelAccept(struct mwServiceFileTransfer *srvc, | |
176 struct mwChannel *chan, | |
177 struct mwMsgChannelAccept *msg) { | |
178 | |
179 struct mwFileTransferHandler *handler; | |
180 struct mwFileTransfer *ft; | |
181 | |
182 g_return_if_fail(srvc->handler != NULL); | |
183 handler = srvc->handler; | |
184 | |
185 ft = mwChannel_getServiceData(chan); | |
186 g_return_if_fail(ft != NULL); | |
187 | |
188 ft_state(ft, mwFileTransfer_OPEN); | |
189 | |
190 if(handler->ft_opened) | |
191 handler->ft_opened(ft); | |
192 } | |
193 | |
194 | |
195 static void recv_channelDestroy(struct mwServiceFileTransfer *srvc, | |
196 struct mwChannel *chan, | |
197 struct mwMsgChannelDestroy *msg) { | |
198 | |
199 struct mwFileTransferHandler *handler; | |
200 struct mwFileTransfer *ft; | |
201 guint32 code; | |
202 | |
203 code = msg->reason; | |
204 | |
205 g_return_if_fail(srvc->handler != NULL); | |
206 handler = srvc->handler; | |
207 | |
208 ft = mwChannel_getServiceData(chan); | |
209 g_return_if_fail(ft != NULL); | |
210 | |
211 ft->channel = NULL; | |
212 | |
213 if(! mwFileTransfer_isDone(ft)) | |
214 ft_state(ft, mwFileTransfer_CANCEL_REMOTE); | |
215 | |
216 mwFileTransfer_close(ft, code); | |
217 } | |
218 | |
219 | |
220 static void recv_TRANSFER(struct mwFileTransfer *ft, | |
221 struct mwOpaque *data) { | |
222 | |
223 struct mwServiceFileTransfer *srvc; | |
224 struct mwFileTransferHandler *handler; | |
225 | |
226 srvc = ft->service; | |
227 handler = srvc->handler; | |
228 | |
229 g_return_if_fail(mwFileTransfer_isOpen(ft)); | |
230 | |
231 if(data->len > ft->remaining) { | |
232 /* @todo handle error */ | |
233 | |
234 } else { | |
235 ft->remaining -= data->len; | |
236 | |
237 if(! ft->remaining) | |
238 ft_state(ft, mwFileTransfer_DONE); | |
239 | |
240 if(handler->ft_recv) | |
241 handler->ft_recv(ft, data); | |
242 } | |
243 } | |
244 | |
245 | |
246 static void recv_RECEIVED(struct mwFileTransfer *ft, | |
247 struct mwOpaque *data) { | |
248 | |
249 struct mwServiceFileTransfer *srvc; | |
250 struct mwFileTransferHandler *handler; | |
251 | |
252 srvc = ft->service; | |
253 handler = srvc->handler; | |
254 | |
255 if(! ft->remaining) | |
256 ft_state(ft, mwFileTransfer_DONE); | |
257 | |
258 if(handler->ft_ack) | |
259 handler->ft_ack(ft); | |
260 | |
261 if(! ft->remaining) | |
262 mwFileTransfer_close(ft, mwFileTransfer_SUCCESS); | |
263 } | |
264 | |
265 | |
266 static void recv(struct mwService *srvc, struct mwChannel *chan, | |
267 guint16 type, struct mwOpaque *data) { | |
268 | |
269 struct mwFileTransfer *ft; | |
270 | |
271 ft = mwChannel_getServiceData(chan); | |
272 g_return_if_fail(ft != NULL); | |
273 | |
274 switch(type) { | |
275 case msg_TRANSFER: | |
276 recv_TRANSFER(ft, data); | |
277 break; | |
278 | |
279 case msg_RECEIVED: | |
280 recv_RECEIVED(ft, data); | |
281 break; | |
282 | |
283 default: | |
284 mw_debug_mailme(data, "unknown message in ft service: 0x%04x", type); | |
285 } | |
286 } | |
287 | |
288 | |
289 static void clear(struct mwServiceFileTransfer *srvc) { | |
290 struct mwFileTransferHandler *h; | |
291 | |
292 h = srvc->handler; | |
293 if(h && h->clear) | |
294 h->clear(srvc); | |
295 srvc->handler = NULL; | |
296 } | |
297 | |
298 | |
299 static const char *name(struct mwService *srvc) { | |
300 return "File Transfer"; | |
301 } | |
302 | |
303 | |
304 static const char *desc(struct mwService *srvc) { | |
305 return "Provides file transfer capabilities through the community server"; | |
306 } | |
307 | |
308 | |
309 static void start(struct mwService *srvc) { | |
310 mwService_started(srvc); | |
311 } | |
312 | |
313 | |
314 static void stop(struct mwServiceFileTransfer *srvc) { | |
315 while(srvc->transfers) { | |
316 mwFileTransfer_free(srvc->transfers->data); | |
317 } | |
318 | |
319 mwService_stopped(MW_SERVICE(srvc)); | |
320 } | |
321 | |
322 | |
323 struct mwServiceFileTransfer * | |
324 mwServiceFileTransfer_new(struct mwSession *session, | |
325 struct mwFileTransferHandler *handler) { | |
326 | |
327 struct mwServiceFileTransfer *srvc_ft; | |
328 struct mwService *srvc; | |
329 | |
330 g_return_val_if_fail(session != NULL, NULL); | |
331 g_return_val_if_fail(handler != NULL, NULL); | |
332 | |
333 srvc_ft = g_new0(struct mwServiceFileTransfer, 1); | |
334 srvc = MW_SERVICE(srvc_ft); | |
335 | |
336 mwService_init(srvc, session, mwService_FILE_TRANSFER); | |
337 srvc->recv_create = (mwService_funcRecvCreate) recv_channelCreate; | |
338 srvc->recv_accept = (mwService_funcRecvAccept) recv_channelAccept; | |
339 srvc->recv_destroy = (mwService_funcRecvDestroy) recv_channelDestroy; | |
340 srvc->recv = recv; | |
341 srvc->clear = (mwService_funcClear) clear; | |
342 srvc->get_name = name; | |
343 srvc->get_desc = desc; | |
344 srvc->start = start; | |
345 srvc->stop = (mwService_funcStop) stop; | |
346 | |
347 srvc_ft->handler = handler; | |
348 | |
349 return srvc_ft; | |
350 } | |
351 | |
352 | |
353 struct mwFileTransferHandler * | |
354 mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc) { | |
355 g_return_val_if_fail(srvc != NULL, NULL); | |
356 return srvc->handler; | |
357 } | |
358 | |
359 | |
360 struct mwFileTransfer * | |
361 mwFileTransfer_new(struct mwServiceFileTransfer *srvc, | |
362 const struct mwIdBlock *who, const char *msg, | |
363 const char *filename, guint32 filesize) { | |
364 | |
365 struct mwFileTransfer *ft; | |
366 | |
367 g_return_val_if_fail(srvc != NULL, NULL); | |
368 g_return_val_if_fail(who != NULL, NULL); | |
369 | |
370 ft = g_new0(struct mwFileTransfer, 1); | |
371 ft->service = srvc; | |
372 mwIdBlock_clone(&ft->who, who); | |
373 ft->filename = g_strdup(filename); | |
374 ft->message = g_strdup(msg); | |
375 ft->size = ft->remaining = filesize; | |
376 | |
377 ft_state(ft, mwFileTransfer_NEW); | |
378 | |
379 /* stick a reference in the service */ | |
380 srvc->transfers = g_list_prepend(srvc->transfers, ft); | |
381 | |
382 return ft; | |
383 } | |
384 | |
385 | |
386 struct mwServiceFileTransfer * | |
387 mwFileTransfer_getService(struct mwFileTransfer *ft) { | |
388 g_return_val_if_fail(ft != NULL, NULL); | |
389 return ft->service; | |
390 } | |
391 | |
392 | |
393 enum mwFileTransferState | |
394 mwFileTransfer_getState(struct mwFileTransfer *ft) { | |
395 g_return_val_if_fail(ft != NULL, mwFileTransfer_UNKNOWN); | |
396 return ft->state; | |
397 } | |
398 | |
399 | |
400 const struct mwIdBlock * | |
401 mwFileTransfer_getUser(struct mwFileTransfer *ft) { | |
402 g_return_val_if_fail(ft != NULL, NULL); | |
403 return &ft->who; | |
404 } | |
405 | |
406 | |
407 const char * | |
408 mwFileTransfer_getMessage(struct mwFileTransfer *ft) { | |
409 g_return_val_if_fail(ft != NULL, NULL); | |
410 return ft->message; | |
411 } | |
412 | |
413 | |
414 const char * | |
415 mwFileTransfer_getFileName(struct mwFileTransfer *ft) { | |
416 g_return_val_if_fail(ft != NULL, NULL); | |
417 return ft->filename; | |
418 } | |
419 | |
420 | |
421 guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft) { | |
422 g_return_val_if_fail(ft != NULL, 0); | |
423 return ft->size; | |
424 } | |
425 | |
426 | |
427 guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft) { | |
428 g_return_val_if_fail(ft != NULL, 0); | |
429 return ft->remaining; | |
430 } | |
431 | |
432 | |
433 int mwFileTransfer_accept(struct mwFileTransfer *ft) { | |
434 struct mwServiceFileTransfer *srvc; | |
435 struct mwFileTransferHandler *handler; | |
436 int ret; | |
437 | |
438 g_return_val_if_fail(ft != NULL, -1); | |
439 g_return_val_if_fail(ft->channel != NULL, -1); | |
440 g_return_val_if_fail(mwFileTransfer_isPending(ft), -1); | |
441 g_return_val_if_fail(mwChannel_isIncoming(ft->channel), -1); | |
442 g_return_val_if_fail(mwChannel_isState(ft->channel, mwChannel_WAIT), -1); | |
443 | |
444 g_return_val_if_fail(ft->service != NULL, -1); | |
445 srvc = ft->service; | |
446 | |
447 g_return_val_if_fail(srvc->handler != NULL, -1); | |
448 handler = srvc->handler; | |
449 | |
450 ret = mwChannel_accept(ft->channel); | |
451 | |
452 if(ret) { | |
453 mwFileTransfer_close(ft, ERR_FAILURE); | |
454 | |
455 } else { | |
456 ft_state(ft, mwFileTransfer_OPEN); | |
457 if(handler->ft_opened) | |
458 handler->ft_opened(ft); | |
459 } | |
460 | |
461 return ret; | |
462 } | |
463 | |
464 | |
465 static void ft_create_chan(struct mwFileTransfer *ft) { | |
466 struct mwSession *s; | |
467 struct mwChannelSet *cs; | |
468 struct mwChannel *chan; | |
469 struct mwLoginInfo *login; | |
470 struct mwPutBuffer *b; | |
471 | |
472 /* we only should be calling this if there isn't a channel already | |
473 associated with the conversation */ | |
474 g_return_if_fail(ft != NULL); | |
475 g_return_if_fail(mwFileTransfer_isNew(ft)); | |
476 g_return_if_fail(ft->channel == NULL); | |
477 | |
478 s = mwService_getSession(MW_SERVICE(ft->service)); | |
479 cs = mwSession_getChannels(s); | |
480 | |
481 chan = mwChannel_newOutgoing(cs); | |
482 mwChannel_setService(chan, MW_SERVICE(ft->service)); | |
483 mwChannel_setProtoType(chan, PROTOCOL_TYPE); | |
484 mwChannel_setProtoVer(chan, PROTOCOL_VER); | |
485 | |
486 /* offer all known ciphers */ | |
487 mwChannel_populateSupportedCipherInstances(chan); | |
488 | |
489 /* set the target */ | |
490 login = mwChannel_getUser(chan); | |
491 login->user_id = g_strdup(ft->who.user); | |
492 login->community = g_strdup(ft->who.community); | |
493 | |
494 /* compose the addtl create */ | |
495 b = mwPutBuffer_new(); | |
496 guint32_put(b, 0x00); | |
497 mwString_put(b, ft->filename); | |
498 mwString_put(b, ft->message); | |
499 guint32_put(b, ft->size); | |
500 guint32_put(b, 0x00); | |
501 guint16_put(b, 0x00); | |
502 | |
503 mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b); | |
504 | |
505 ft->channel = mwChannel_create(chan)? NULL: chan; | |
506 if(ft->channel) { | |
507 mwChannel_setServiceData(ft->channel, ft, NULL); | |
508 } | |
509 } | |
510 | |
511 | |
512 int mwFileTransfer_offer(struct mwFileTransfer *ft) { | |
513 struct mwServiceFileTransfer *srvc; | |
514 struct mwFileTransferHandler *handler; | |
515 | |
516 g_return_val_if_fail(ft != NULL, -1); | |
517 g_return_val_if_fail(ft->channel == NULL, -1); | |
518 g_return_val_if_fail(mwFileTransfer_isNew(ft), -1); | |
519 | |
520 g_return_val_if_fail(ft->service != NULL, -1); | |
521 srvc = ft->service; | |
522 | |
523 g_return_val_if_fail(srvc->handler != NULL, -1); | |
524 handler = srvc->handler; | |
525 | |
526 ft_create_chan(ft); | |
527 if(ft->channel) { | |
528 ft_state(ft, mwFileTransfer_PENDING); | |
529 } else { | |
530 ft_state(ft, mwFileTransfer_ERROR); | |
531 mwFileTransfer_close(ft, ERR_FAILURE); | |
532 } | |
533 | |
534 return 0; | |
535 } | |
536 | |
537 | |
538 int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code) { | |
539 struct mwServiceFileTransfer *srvc; | |
540 struct mwFileTransferHandler *handler; | |
10977
2ce8ec01a064
[gaim-migrate @ 12803]
Christopher O'Brien <siege@pidgin.im>
parents:
10969
diff
changeset
|
541 int ret = 0; |
10969 | 542 |
543 g_return_val_if_fail(ft != NULL, -1); | |
544 | |
545 if(mwFileTransfer_isOpen(ft)) | |
546 ft_state(ft, mwFileTransfer_CANCEL_LOCAL); | |
547 | |
548 if(ft->channel) { | |
549 ret = mwChannel_destroy(ft->channel, code, NULL); | |
550 ft->channel = NULL; | |
551 } | |
552 | |
553 srvc = ft->service; | |
554 g_return_val_if_fail(srvc != NULL, ret); | |
555 | |
556 handler = srvc->handler; | |
557 g_return_val_if_fail(handler != NULL, ret); | |
558 | |
559 if(handler->ft_closed) | |
560 handler->ft_closed(ft, code); | |
561 | |
562 return ret; | |
563 } | |
564 | |
565 | |
566 void mwFileTransfer_free(struct mwFileTransfer *ft) { | |
567 struct mwServiceFileTransfer *srvc; | |
568 | |
569 if(! ft) return; | |
570 | |
571 srvc = ft->service; | |
572 if(srvc) | |
573 srvc->transfers = g_list_remove(srvc->transfers, ft); | |
574 | |
575 if(ft->channel) { | |
576 mwChannel_destroy(ft->channel, mwFileTransfer_SUCCESS, NULL); | |
577 ft->channel = NULL; | |
578 } | |
579 | |
580 mwFileTransfer_removeClientData(ft); | |
581 | |
582 mwIdBlock_clear(&ft->who); | |
583 g_free(ft->filename); | |
584 g_free(ft->message); | |
585 g_free(ft); | |
586 } | |
587 | |
588 | |
589 int mwFileTransfer_send(struct mwFileTransfer *ft, | |
590 struct mwOpaque *data) { | |
591 | |
592 struct mwChannel *chan; | |
593 int ret; | |
594 | |
595 g_return_val_if_fail(ft != NULL, -1); | |
596 g_return_val_if_fail(mwFileTransfer_isOpen(ft), -1); | |
597 g_return_val_if_fail(ft->channel != NULL, -1); | |
598 chan = ft->channel; | |
599 | |
600 g_return_val_if_fail(mwChannel_isOutgoing(chan), -1); | |
601 | |
602 if(data->len > ft->remaining) { | |
603 /* @todo handle error */ | |
604 return -1; | |
605 } | |
606 | |
607 ret = mwChannel_send(chan, msg_TRANSFER, data); | |
608 if(! ret) ft->remaining -= data->len; | |
609 | |
610 /* we're not done until we receive an ACK for the last piece of | |
611 outgoing data */ | |
612 | |
613 return ret; | |
614 } | |
615 | |
616 | |
617 int mwFileTransfer_ack(struct mwFileTransfer *ft) { | |
618 struct mwChannel *chan; | |
619 | |
620 g_return_val_if_fail(ft != NULL, -1); | |
621 | |
622 chan = ft->channel; | |
623 g_return_val_if_fail(chan != NULL, -1); | |
624 g_return_val_if_fail(mwChannel_isIncoming(chan), -1); | |
625 | |
626 return mwChannel_sendEncrypted(chan, msg_RECEIVED, NULL, FALSE); | |
627 } | |
628 | |
629 | |
630 void mwFileTransfer_setClientData(struct mwFileTransfer *ft, | |
631 gpointer data, GDestroyNotify clean) { | |
632 g_return_if_fail(ft != NULL); | |
633 mw_datum_set(&ft->client_data, data, clean); | |
634 } | |
635 | |
636 | |
637 gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft) { | |
638 g_return_val_if_fail(ft != NULL, NULL); | |
639 return mw_datum_get(&ft->client_data); | |
640 } | |
641 | |
642 | |
643 void mwFileTransfer_removeClientData(struct mwFileTransfer *ft) { | |
644 g_return_if_fail(ft != NULL); | |
645 mw_datum_clear(&ft->client_data); | |
646 } | |
647 |