2009-07-28 [colin] 3.7.2cvs12
[claws.git] / src / common / session.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2009 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <time.h>
34 #include <errno.h>
35
36 #include "session.h"
37 #include "utils.h"
38 #include "log.h"
39
40 static gint session_connect_cb          (SockInfo       *sock,
41                                          gpointer        data);
42 static gint session_close               (Session        *session);
43
44 static gboolean session_timeout_cb      (gpointer        data);
45
46 static gboolean session_recv_msg_idle_cb        (gpointer        data);
47 static gboolean session_recv_data_idle_cb       (gpointer        data);
48
49 static gboolean session_read_msg_cb     (SockInfo       *source,
50                                          GIOCondition    condition,
51                                          gpointer        data);
52 static gboolean session_read_data_cb    (SockInfo       *source,
53                                          GIOCondition    condition,
54                                          gpointer        data);
55 static gboolean session_write_msg_cb    (SockInfo       *source,
56                                          GIOCondition    condition,
57                                          gpointer        data);
58 static gboolean session_write_data_cb   (SockInfo       *source,
59                                          GIOCondition    condition,
60                                          gpointer        data);
61
62
63 void session_init(Session *session, const void *prefs_account, gboolean is_smtp)
64 {
65         session->type = SESSION_UNKNOWN;
66         session->sock = NULL;
67         session->server = NULL;
68         session->port = 0;
69 #ifdef USE_GNUTLS
70         session->ssl_type = SSL_NONE;
71 #endif
72         session->nonblocking = TRUE;
73         session->state = SESSION_READY;
74         session->last_access_time = time(NULL);
75
76         g_get_current_time(&session->tv_prev);
77
78         session->conn_id = 0;
79
80         session->io_tag = 0;
81
82         session->read_buf_p = session->read_buf;
83         session->read_buf_len = 0;
84
85         session->read_msg_buf = g_string_sized_new(1024);
86         session->read_data_buf = g_byte_array_new();
87
88         session->write_buf = NULL;
89         session->write_buf_p = NULL;
90         session->write_buf_len = 0;
91
92         session->write_data = NULL;
93         session->write_data_p = NULL;
94         session->write_data_len = 0;
95
96         session->timeout_tag = 0;
97         session->timeout_interval = 0;
98
99         session->data = NULL;
100         session->account = prefs_account;
101         session->is_smtp = is_smtp;
102 }
103
104 /*!
105  *\brief        Set up parent and child process
106  *              Childloop: Read commands from parent,
107  *              send to server, get answer, pass to parent
108  *
109  *\param        session Contains session information
110  *              server to connect to
111  *              port to connect to
112  *
113  *\return        0 : success
114  *              -1 : pipe / fork errors (parent)
115  *               1 : connection error (child)
116  */
117 gint session_connect(Session *session, const gchar *server, gushort port)
118 {
119 #ifdef G_OS_UNIX
120         session->server = g_strdup(server);
121         session->port = port;
122
123         session->conn_id = sock_connect_async(server, port, session_connect_cb,
124                                               session);
125         if (session->conn_id < 0) {
126                 g_warning("can't connect to server.");
127                 session_close(session);
128                 return -1;
129         }
130
131         return 0;
132 #else
133         SockInfo *sock;
134
135         session->server = g_strdup(server);
136         session->port = port;
137
138         sock = sock_connect(server, port);
139         if (sock == NULL) {
140                 g_warning("can't connect to server.");
141                 session_close(session);
142                 return -1;
143         }
144         sock->is_smtp = session->is_smtp;
145
146         return session_connect_cb(sock, session);
147 #endif
148 }
149
150 static gint session_connect_cb(SockInfo *sock, gpointer data)
151 {
152         Session *session = SESSION(data);
153
154         session->conn_id = 0;
155
156         if (!sock) {
157                 g_warning("can't connect to server.");
158                 session->state = SESSION_ERROR;
159                 return -1;
160         }
161
162         session->sock = sock;
163         sock->account = session->account;
164         sock->is_smtp = session->is_smtp;
165 #ifdef USE_GNUTLS
166         if (session->ssl_type == SSL_TUNNEL) {
167                 sock_set_nonblocking_mode(sock, FALSE);
168                 if (!ssl_init_socket(sock)) {
169                         g_warning("can't initialize SSL.");
170                         log_error(LOG_PROTOCOL, _("SSL handshake failed\n"));
171                         session->state = SESSION_ERROR;
172                         return -1;
173                 }
174         }
175 #endif
176
177         /* we could have gotten a timeout while waiting for user input in 
178          * an SSL certificate dialog */
179         if (session->state == SESSION_TIMEOUT)
180                 return -1;
181
182         sock_set_nonblocking_mode(sock, session->nonblocking);
183
184         debug_print("session (%p): connected\n", session);
185
186         session->state = SESSION_RECV;
187         session->io_tag = sock_add_watch(session->sock, G_IO_IN,
188                                          session_read_msg_cb,
189                                          session);
190
191         return 0;
192 }
193
194 /*!
195  *\brief        child and parent: send DISCONNECT message to other process
196  *
197  *\param        session Contains session information
198  *
199  *\return        0 : success
200  */
201 gint session_disconnect(Session *session)
202 {
203         session_close(session);
204         return 0;
205 }
206
207 /*!
208  *\brief        parent ?
209  *
210  *\param        session Contains session information
211  */
212 void session_destroy(Session *session)
213 {
214         cm_return_if_fail(session != NULL);
215         cm_return_if_fail(session->destroy != NULL);
216
217         session_close(session);
218         session->destroy(session);
219         g_free(session->server);
220         g_string_free(session->read_msg_buf, TRUE);
221         g_byte_array_free(session->read_data_buf, TRUE);
222         g_free(session->read_data_terminator);
223         g_free(session->write_buf);
224
225         debug_print("session (%p): destroyed\n", session);
226
227         g_free(session);
228 }
229
230 gboolean session_is_connected(Session *session)
231 {
232         return (session->state == SESSION_READY ||
233                 session->state == SESSION_SEND ||
234                 session->state == SESSION_RECV);
235 }
236
237 void session_set_access_time(Session *session)
238 {
239         session->last_access_time = time(NULL);
240 }
241
242 void session_set_timeout(Session *session, guint interval)
243 {
244         if (session->timeout_tag > 0)
245                 g_source_remove(session->timeout_tag);
246
247         session->timeout_interval = interval;
248         if (interval > 0) {
249 #if GLIB_CHECK_VERSION(2,14,0)
250                 if (interval % 1000 == 0)
251                         session->timeout_tag =
252                                 g_timeout_add_seconds(interval/1000, session_timeout_cb, session);
253                 else
254 #endif
255                 session->timeout_tag =
256                         g_timeout_add(interval, session_timeout_cb, session);
257         } else
258                 session->timeout_tag = 0;
259 }
260
261 static gboolean session_timeout_cb(gpointer data)
262 {
263         Session *session = SESSION(data);
264
265         g_warning("session timeout.\n");
266
267         if (session->io_tag > 0) {
268                 g_source_remove(session->io_tag);
269                 session->io_tag = 0;
270         }
271
272         session->timeout_tag = 0;
273         session->state = SESSION_TIMEOUT;
274
275         return FALSE;
276 }
277
278 void session_set_recv_message_notify(Session *session,
279                                      RecvMsgNotify notify_func, gpointer data)
280 {
281         session->recv_msg_notify = notify_func;
282         session->recv_msg_notify_data = data;
283 }
284
285 void session_set_recv_data_progressive_notify
286                                         (Session *session,
287                                          RecvDataProgressiveNotify notify_func,
288                                          gpointer data)
289 {
290         session->recv_data_progressive_notify = notify_func,
291         session->recv_data_progressive_notify_data = data;
292 }
293
294 void session_set_recv_data_notify(Session *session, RecvDataNotify notify_func,
295                                   gpointer data)
296 {
297         session->recv_data_notify = notify_func;
298         session->recv_data_notify_data = data;
299 }
300
301 void session_set_send_data_progressive_notify
302                                         (Session *session,
303                                          SendDataProgressiveNotify notify_func,
304                                          gpointer data)
305 {
306         session->send_data_progressive_notify = notify_func;
307         session->send_data_progressive_notify_data = data;
308 }
309
310 void session_set_send_data_notify(Session *session, SendDataNotify notify_func,
311                                   gpointer data)
312 {
313         session->send_data_notify = notify_func;
314         session->send_data_notify_data = data;
315 }
316
317 /*!
318  *\brief        child and parent cleanup (child closes first)
319  *
320  *\param        session Contains session information
321  *
322  *\return        0 : success
323  */
324 static gint session_close(Session *session)
325 {
326         cm_return_val_if_fail(session != NULL, -1);
327
328 #ifdef G_OS_UNIX
329         if (session->conn_id > 0) {
330                 sock_connect_async_cancel(session->conn_id);
331                 session->conn_id = 0;
332                 debug_print("session (%p): connection cancelled\n", session);
333         }
334 #endif
335
336         session_set_timeout(session, 0);
337
338         if (session->io_tag > 0) {
339                 g_source_remove(session->io_tag);
340                 session->io_tag = 0;
341         }
342
343         if (session->sock) {
344                 sock_close(session->sock);
345                 session->sock = NULL;
346                 session->state = SESSION_DISCONNECTED;
347                 debug_print("session (%p): closed\n", session);
348         }
349
350         return 0;
351 }
352
353 #ifdef USE_GNUTLS
354 gint session_start_tls(Session *session)
355 {
356         gboolean nb_mode;
357
358         nb_mode = sock_is_nonblocking_mode(session->sock);
359
360         if (nb_mode)
361                 sock_set_nonblocking_mode(session->sock, FALSE);
362
363         if (!ssl_init_socket_with_method(session->sock, SSL_METHOD_TLSv1)) {
364                 g_warning("couldn't start TLS session.\n");
365                 if (nb_mode)
366                         sock_set_nonblocking_mode(session->sock, session->nonblocking);
367                 return -1;
368         }
369
370         if (nb_mode)
371                 sock_set_nonblocking_mode(session->sock, session->nonblocking);
372
373         return 0;
374 }
375 #endif
376
377 gint session_send_msg(Session *session, SessionMsgType type, const gchar *msg)
378 {
379         gboolean ret;
380
381         cm_return_val_if_fail(session->write_buf == NULL, -1);
382         cm_return_val_if_fail(msg != NULL, -1);
383         cm_return_val_if_fail(msg[0] != '\0', -1);
384
385         session->state = SESSION_SEND;
386         session->write_buf = g_strconcat(msg, "\r\n", NULL);
387         session->write_buf_p = session->write_buf;
388         session->write_buf_len = strlen(msg) + 2;
389
390         ret = session_write_msg_cb(session->sock, G_IO_OUT, session);
391
392         if (ret == TRUE)
393                 session->io_tag = sock_add_watch(session->sock, G_IO_OUT,
394                                                  session_write_msg_cb, session);
395         else if (session->state == SESSION_ERROR)
396                 return -1;
397
398         return 0;
399 }
400
401 gint session_recv_msg(Session *session)
402 {
403         cm_return_val_if_fail(session->read_msg_buf->len == 0, -1);
404
405         session->state = SESSION_RECV;
406
407         if (session->read_buf_len > 0)
408                 g_idle_add(session_recv_msg_idle_cb, session);
409         else
410                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
411                                                  session_read_msg_cb, session);
412
413         return 0;
414 }
415
416 static gboolean session_recv_msg_idle_cb(gpointer data)
417 {
418         Session *session = SESSION(data);
419         gboolean ret;
420
421         ret = session_read_msg_cb(session->sock, G_IO_IN, session);
422
423         if (ret == TRUE)
424                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
425                                                  session_read_msg_cb, session);
426
427         return FALSE;
428 }
429
430 /*!
431  *\brief        parent (child?): send data to other process
432  *
433  *\param        session Contains session information
434  *              data Data to send
435  *              size Bytes to send
436  *
437  *\return        0 : success
438  *              -1 : error
439  */
440 gint session_send_data(Session *session, const guchar *data, guint size)
441 {
442         gboolean ret;
443
444         cm_return_val_if_fail(session->write_data == NULL, -1);
445         cm_return_val_if_fail(data != NULL, -1);
446         cm_return_val_if_fail(size != 0, -1);
447
448         session->state = SESSION_SEND;
449
450         session->write_data = data;
451         session->write_data_p = session->write_data;
452         session->write_data_len = size;
453         g_get_current_time(&session->tv_prev);
454
455         ret = session_write_data_cb(session->sock, G_IO_OUT, session);
456
457         if (ret == TRUE)
458                 session->io_tag = sock_add_watch(session->sock, G_IO_OUT,
459                                                  session_write_data_cb,
460                                                  session);
461         else if (session->state == SESSION_ERROR)
462                 return -1;
463
464         return 0;
465 }
466
467 gint session_recv_data(Session *session, guint size, const gchar *terminator)
468 {
469         cm_return_val_if_fail(session->read_data_buf->len == 0, -1);
470
471         session->state = SESSION_RECV;
472
473         g_free(session->read_data_terminator);
474         session->read_data_terminator = g_strdup(terminator);
475         g_get_current_time(&session->tv_prev);
476
477         if (session->read_buf_len > 0)
478                 g_idle_add(session_recv_data_idle_cb, session);
479         else
480                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
481                                                  session_read_data_cb, session);
482
483         return 0;
484 }
485
486 static gboolean session_recv_data_idle_cb(gpointer data)
487 {
488         Session *session = SESSION(data);
489         gboolean ret;
490
491         ret = session_read_data_cb(session->sock, G_IO_IN, session);
492
493         if (ret == TRUE)
494                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
495                                                  session_read_data_cb, session);
496
497         return FALSE;
498 }
499
500 static gboolean session_read_msg_cb(SockInfo *source, GIOCondition condition,
501                                     gpointer data)
502 {
503         Session *session = SESSION(data);
504         gchar buf[SESSION_BUFFSIZE];
505         gint line_len;
506         gchar *newline;
507         gchar *msg;
508         gint ret;
509
510         cm_return_val_if_fail(condition == G_IO_IN, FALSE);
511
512         session_set_timeout(session, session->timeout_interval);
513
514         if (session->read_buf_len == 0) {
515                 gint read_len;
516
517                 read_len = sock_read(session->sock, session->read_buf,
518                                      SESSION_BUFFSIZE - 1);
519
520                 if (read_len == -1 && session->state == SESSION_DISCONNECTED) {
521                         g_warning ("sock_read: session disconnected\n");
522                         if (session->io_tag > 0) {
523                                 g_source_remove(session->io_tag);
524                                 session->io_tag = 0;
525                         }
526                         return FALSE;
527                 }
528                 
529                 if (read_len == 0) {
530                         g_warning("sock_read: received EOF\n");
531                         session->state = SESSION_EOF;
532                         return FALSE;
533                 }
534
535                 if (read_len < 0) {
536                         switch (errno) {
537                         case EAGAIN:
538                                 return TRUE;
539                         default:
540                                 g_warning("sock_read: %s\n", g_strerror(errno));
541                                 session->state = SESSION_ERROR;
542                                 return FALSE;
543                         }
544                 }
545
546                 session->read_buf_len = read_len;
547         }
548
549         if ((newline = memchr(session->read_buf_p, '\n', session->read_buf_len))
550                 != NULL)
551                 line_len = newline - session->read_buf_p + 1;
552         else
553                 line_len = session->read_buf_len;
554
555         if (line_len == 0)
556                 return TRUE;
557
558         memcpy(buf, session->read_buf_p, line_len);
559         buf[line_len] = '\0';
560
561         g_string_append(session->read_msg_buf, buf);
562
563         session->read_buf_len -= line_len;
564         if (session->read_buf_len == 0)
565                 session->read_buf_p = session->read_buf;
566         else
567                 session->read_buf_p += line_len;
568
569         /* incomplete read */
570         if (buf[line_len - 1] != '\n')
571                 return TRUE;
572
573         /* complete */
574         if (session->io_tag > 0) {
575                 g_source_remove(session->io_tag);
576                 session->io_tag = 0;
577         }
578
579         /* callback */
580         msg = g_strdup(session->read_msg_buf->str);
581         strretchomp(msg);
582         g_string_truncate(session->read_msg_buf, 0);
583
584         ret = session->recv_msg(session, msg);
585         session->recv_msg_notify(session, msg, session->recv_msg_notify_data);
586
587         g_free(msg);
588
589         if (ret < 0)
590                 session->state = SESSION_ERROR;
591
592         return FALSE;
593 }
594
595 static gboolean session_read_data_cb(SockInfo *source, GIOCondition condition,
596                                      gpointer data)
597 {
598         Session *session = SESSION(data);
599         GByteArray *data_buf;
600         gint terminator_len;
601         gboolean complete = FALSE;
602         guint data_len;
603         gint ret;
604
605         cm_return_val_if_fail(condition == G_IO_IN, FALSE);
606
607         session_set_timeout(session, session->timeout_interval);
608
609         if (session->read_buf_len == 0) {
610                 gint read_len;
611
612                 read_len = sock_read(session->sock, session->read_buf,
613                                      SESSION_BUFFSIZE);
614
615                 if (read_len == 0) {
616                         g_warning("sock_read: received EOF\n");
617                         session->state = SESSION_EOF;
618                         return FALSE;
619                 }
620
621                 if (read_len < 0) {
622                         switch (errno) {
623                         case EAGAIN:
624                                 return TRUE;
625                         default:
626                                 g_warning("sock_read: %s\n", g_strerror(errno));
627                                 session->state = SESSION_ERROR;
628                                 return FALSE;
629                         }
630                 }
631
632                 session->read_buf_len = read_len;
633         }
634
635         data_buf = session->read_data_buf;
636         terminator_len = strlen(session->read_data_terminator);
637
638         if (session->read_buf_len == 0)
639                 return TRUE;
640
641         g_byte_array_append(data_buf, session->read_buf_p,
642                             session->read_buf_len);
643
644         session->read_buf_len = 0;
645         session->read_buf_p = session->read_buf;
646
647         /* check if data is terminated */
648         if (data_buf->len >= terminator_len) {
649                 if (memcmp(data_buf->data, session->read_data_terminator,
650                            terminator_len) == 0)
651                         complete = TRUE;
652                 else if (data_buf->len >= terminator_len + 2 &&
653                          memcmp(data_buf->data + data_buf->len -
654                                 (terminator_len + 2), "\r\n", 2) == 0 &&
655                          memcmp(data_buf->data + data_buf->len -
656                                 terminator_len, session->read_data_terminator,
657                                 terminator_len) == 0)
658                         complete = TRUE;
659         }
660
661         /* incomplete read */
662         if (!complete) {
663                 GTimeVal tv_cur;
664
665                 g_get_current_time(&tv_cur);
666                 if (tv_cur.tv_sec - session->tv_prev.tv_sec > 0 ||
667                     tv_cur.tv_usec - session->tv_prev.tv_usec >
668                     UI_REFRESH_INTERVAL) {
669                         session->recv_data_progressive_notify
670                                 (session, data_buf->len, 0,
671                                  session->recv_data_progressive_notify_data);
672                         g_get_current_time(&session->tv_prev);
673                 }
674                 return TRUE;
675         }
676
677         /* complete */
678         if (session->io_tag > 0) {
679                 g_source_remove(session->io_tag);
680                 session->io_tag = 0;
681         }
682
683         data_len = data_buf->len - terminator_len;
684
685         /* callback */
686         ret = session->recv_data_finished(session, (gchar *)data_buf->data,
687                                           data_len);
688
689         g_byte_array_set_size(data_buf, 0);
690
691         session->recv_data_notify(session, data_len,
692                                   session->recv_data_notify_data);
693
694         if (ret < 0)
695                 session->state = SESSION_ERROR;
696
697         return FALSE;
698 }
699
700 static gint session_write_buf(Session *session)
701 {
702         gint write_len;
703         gint to_write_len;
704
705         cm_return_val_if_fail(session->write_buf != NULL, -1);
706         cm_return_val_if_fail(session->write_buf_p != NULL, -1);
707         cm_return_val_if_fail(session->write_buf_len > 0, -1);
708
709         to_write_len = session->write_buf_len -
710                 (session->write_buf_p - session->write_buf);
711         to_write_len = MIN(to_write_len, SESSION_BUFFSIZE);
712
713         write_len = sock_write(session->sock, session->write_buf_p,
714                                to_write_len);
715
716         if (write_len < 0) {
717                 switch (errno) {
718                 case EAGAIN:
719                         write_len = 0;
720                         break;
721                 default:
722                         g_warning("sock_write: %s\n", g_strerror(errno));
723                         session->state = SESSION_ERROR;
724                         return -1;
725                 }
726         }
727
728         /* incomplete write */
729         if (session->write_buf_p - session->write_buf + write_len <
730             session->write_buf_len) {
731                 session->write_buf_p += write_len;
732                 return 1;
733         }
734
735         g_free(session->write_buf);
736         session->write_buf = NULL;
737         session->write_buf_p = NULL;
738         session->write_buf_len = 0;
739
740         return 0;
741 }
742
743 static gint session_write_data(Session *session)
744 {
745         gint write_len;
746         gint to_write_len;
747
748         cm_return_val_if_fail(session->write_data != NULL, -1);
749         cm_return_val_if_fail(session->write_data_p != NULL, -1);
750         cm_return_val_if_fail(session->write_data_len > 0, -1);
751
752         to_write_len = session->write_data_len -
753                 (session->write_data_p - session->write_data);
754         to_write_len = MIN(to_write_len, SESSION_BUFFSIZE);
755
756         write_len = sock_write(session->sock, session->write_data_p,
757                                to_write_len);
758
759         if (write_len < 0) {
760                 switch (errno) {
761                 case EAGAIN:
762                         write_len = 0;
763                         break;
764                 default:
765                         g_warning("sock_write: %s\n", g_strerror(errno));
766                         session->state = SESSION_ERROR;
767                         return -1;
768                 }
769         }
770
771         /* incomplete write */
772         if (session->write_data_p - session->write_data + write_len <
773             session->write_data_len) {
774                 session->write_data_p += write_len;
775                 return 1;
776         }
777
778         session->write_data = NULL;
779         session->write_data_p = NULL;
780         session->write_data_len = 0;
781
782         return 0;
783 }
784
785 static gboolean session_write_msg_cb(SockInfo *source, GIOCondition condition,
786                                      gpointer data)
787 {
788         Session *session = SESSION(data);
789         gint ret;
790
791         cm_return_val_if_fail(condition == G_IO_OUT, FALSE);
792         cm_return_val_if_fail(session->write_buf != NULL, FALSE);
793         cm_return_val_if_fail(session->write_buf_p != NULL, FALSE);
794         cm_return_val_if_fail(session->write_buf_len > 0, FALSE);
795
796         ret = session_write_buf(session);
797
798         if (ret < 0) {
799                 session->state = SESSION_ERROR;
800                 return FALSE;
801         } else if (ret > 0)
802                 return TRUE;
803
804         if (session->io_tag > 0) {
805                 g_source_remove(session->io_tag);
806                 session->io_tag = 0;
807         }
808
809         session_recv_msg(session);
810
811         return FALSE;
812 }
813
814 static gboolean session_write_data_cb(SockInfo *source,
815                                       GIOCondition condition, gpointer data)
816 {
817         Session *session = SESSION(data);
818         guint write_data_len;
819         gint ret;
820
821         cm_return_val_if_fail(condition == G_IO_OUT, FALSE);
822         cm_return_val_if_fail(session->write_data != NULL, FALSE);
823         cm_return_val_if_fail(session->write_data_p != NULL, FALSE);
824         cm_return_val_if_fail(session->write_data_len > 0, FALSE);
825
826         write_data_len = session->write_data_len;
827
828         ret = session_write_data(session);
829
830         if (ret < 0) {
831                 session->state = SESSION_ERROR;
832                 return FALSE;
833         } else if (ret > 0) {
834                 GTimeVal tv_cur;
835
836                 g_get_current_time(&tv_cur);
837                 if (tv_cur.tv_sec - session->tv_prev.tv_sec > 0 ||
838                     tv_cur.tv_usec - session->tv_prev.tv_usec >
839                     UI_REFRESH_INTERVAL) {
840                         session_set_timeout(session, session->timeout_interval);
841                         session->send_data_progressive_notify
842                                 (session,
843                                  session->write_data_p - session->write_data,
844                                  write_data_len,
845                                  session->send_data_progressive_notify_data);
846                         g_get_current_time(&session->tv_prev);
847                 }
848                 return TRUE;
849         }
850
851         if (session->io_tag > 0) {
852                 g_source_remove(session->io_tag);
853                 session->io_tag = 0;
854         }
855
856         /* callback */
857         ret = session->send_data_finished(session, write_data_len);
858         session->send_data_notify(session, write_data_len,
859                                   session->send_data_notify_data);
860
861         return FALSE;
862 }