2008-11-26 [colin] 3.6.1cvs44
[claws.git] / src / common / session.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 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         sock_set_nonblocking_mode(sock, session->nonblocking);
178
179         debug_print("session (%p): connected\n", session);
180
181         session->state = SESSION_RECV;
182         session->io_tag = sock_add_watch(session->sock, G_IO_IN,
183                                          session_read_msg_cb,
184                                          session);
185
186         return 0;
187 }
188
189 /*!
190  *\brief        child and parent: send DISCONNECT message to other process
191  *
192  *\param        session Contains session information
193  *
194  *\return        0 : success
195  */
196 gint session_disconnect(Session *session)
197 {
198         session_close(session);
199         return 0;
200 }
201
202 /*!
203  *\brief        parent ?
204  *
205  *\param        session Contains session information
206  */
207 void session_destroy(Session *session)
208 {
209         g_return_if_fail(session != NULL);
210         g_return_if_fail(session->destroy != NULL);
211
212         session_close(session);
213         session->destroy(session);
214         g_free(session->server);
215         g_string_free(session->read_msg_buf, TRUE);
216         g_byte_array_free(session->read_data_buf, TRUE);
217         g_free(session->read_data_terminator);
218         g_free(session->write_buf);
219
220         debug_print("session (%p): destroyed\n", session);
221
222         g_free(session);
223 }
224
225 gboolean session_is_connected(Session *session)
226 {
227         return (session->state == SESSION_READY ||
228                 session->state == SESSION_SEND ||
229                 session->state == SESSION_RECV);
230 }
231
232 void session_set_access_time(Session *session)
233 {
234         session->last_access_time = time(NULL);
235 }
236
237 void session_set_timeout(Session *session, guint interval)
238 {
239         if (session->timeout_tag > 0)
240                 g_source_remove(session->timeout_tag);
241
242         session->timeout_interval = interval;
243         if (interval > 0) {
244 #if GLIB_CHECK_VERSION(2,14,0)
245                 if (interval % 1000 == 0)
246                         session->timeout_tag =
247                                 g_timeout_add_seconds(interval/1000, session_timeout_cb, session);
248                 else
249 #endif
250                 session->timeout_tag =
251                         g_timeout_add(interval, session_timeout_cb, session);
252         } else
253                 session->timeout_tag = 0;
254 }
255
256 static gboolean session_timeout_cb(gpointer data)
257 {
258         Session *session = SESSION(data);
259
260         g_warning("session timeout.\n");
261
262         if (session->io_tag > 0) {
263                 g_source_remove(session->io_tag);
264                 session->io_tag = 0;
265         }
266
267         session->timeout_tag = 0;
268         session->state = SESSION_TIMEOUT;
269
270         return FALSE;
271 }
272
273 void session_set_recv_message_notify(Session *session,
274                                      RecvMsgNotify notify_func, gpointer data)
275 {
276         session->recv_msg_notify = notify_func;
277         session->recv_msg_notify_data = data;
278 }
279
280 void session_set_recv_data_progressive_notify
281                                         (Session *session,
282                                          RecvDataProgressiveNotify notify_func,
283                                          gpointer data)
284 {
285         session->recv_data_progressive_notify = notify_func,
286         session->recv_data_progressive_notify_data = data;
287 }
288
289 void session_set_recv_data_notify(Session *session, RecvDataNotify notify_func,
290                                   gpointer data)
291 {
292         session->recv_data_notify = notify_func;
293         session->recv_data_notify_data = data;
294 }
295
296 void session_set_send_data_progressive_notify
297                                         (Session *session,
298                                          SendDataProgressiveNotify notify_func,
299                                          gpointer data)
300 {
301         session->send_data_progressive_notify = notify_func;
302         session->send_data_progressive_notify_data = data;
303 }
304
305 void session_set_send_data_notify(Session *session, SendDataNotify notify_func,
306                                   gpointer data)
307 {
308         session->send_data_notify = notify_func;
309         session->send_data_notify_data = data;
310 }
311
312 /*!
313  *\brief        child and parent cleanup (child closes first)
314  *
315  *\param        session Contains session information
316  *
317  *\return        0 : success
318  */
319 static gint session_close(Session *session)
320 {
321         g_return_val_if_fail(session != NULL, -1);
322
323 #ifdef G_OS_UNIX
324         if (session->conn_id > 0) {
325                 sock_connect_async_cancel(session->conn_id);
326                 session->conn_id = 0;
327                 debug_print("session (%p): connection cancelled\n", session);
328         }
329 #endif
330
331         session_set_timeout(session, 0);
332
333         if (session->io_tag > 0) {
334                 g_source_remove(session->io_tag);
335                 session->io_tag = 0;
336         }
337
338         if (session->sock) {
339                 sock_close(session->sock);
340                 session->sock = NULL;
341                 session->state = SESSION_DISCONNECTED;
342                 debug_print("session (%p): closed\n", session);
343         }
344
345         return 0;
346 }
347
348 #ifdef USE_GNUTLS
349 gint session_start_tls(Session *session)
350 {
351         gboolean nb_mode;
352
353         nb_mode = sock_is_nonblocking_mode(session->sock);
354
355         if (nb_mode)
356                 sock_set_nonblocking_mode(session->sock, FALSE);
357
358         if (!ssl_init_socket_with_method(session->sock, SSL_METHOD_TLSv1)) {
359                 g_warning("couldn't start TLS session.\n");
360                 if (nb_mode)
361                         sock_set_nonblocking_mode(session->sock, session->nonblocking);
362                 return -1;
363         }
364
365         if (nb_mode)
366                 sock_set_nonblocking_mode(session->sock, session->nonblocking);
367
368         return 0;
369 }
370 #endif
371
372 gint session_send_msg(Session *session, SessionMsgType type, const gchar *msg)
373 {
374         gboolean ret;
375
376         g_return_val_if_fail(session->write_buf == NULL, -1);
377         g_return_val_if_fail(msg != NULL, -1);
378         g_return_val_if_fail(msg[0] != '\0', -1);
379
380         session->state = SESSION_SEND;
381         session->write_buf = g_strconcat(msg, "\r\n", NULL);
382         session->write_buf_p = session->write_buf;
383         session->write_buf_len = strlen(msg) + 2;
384
385         ret = session_write_msg_cb(session->sock, G_IO_OUT, session);
386
387         if (ret == TRUE)
388                 session->io_tag = sock_add_watch(session->sock, G_IO_OUT,
389                                                  session_write_msg_cb, session);
390         else if (session->state == SESSION_ERROR)
391                 return -1;
392
393         return 0;
394 }
395
396 gint session_recv_msg(Session *session)
397 {
398         g_return_val_if_fail(session->read_msg_buf->len == 0, -1);
399
400         session->state = SESSION_RECV;
401
402         if (session->read_buf_len > 0)
403                 g_idle_add(session_recv_msg_idle_cb, session);
404         else
405                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
406                                                  session_read_msg_cb, session);
407
408         return 0;
409 }
410
411 static gboolean session_recv_msg_idle_cb(gpointer data)
412 {
413         Session *session = SESSION(data);
414         gboolean ret;
415
416         ret = session_read_msg_cb(session->sock, G_IO_IN, session);
417
418         if (ret == TRUE)
419                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
420                                                  session_read_msg_cb, session);
421
422         return FALSE;
423 }
424
425 /*!
426  *\brief        parent (child?): send data to other process
427  *
428  *\param        session Contains session information
429  *              data Data to send
430  *              size Bytes to send
431  *
432  *\return        0 : success
433  *              -1 : error
434  */
435 gint session_send_data(Session *session, const guchar *data, guint size)
436 {
437         gboolean ret;
438
439         g_return_val_if_fail(session->write_data == NULL, -1);
440         g_return_val_if_fail(data != NULL, -1);
441         g_return_val_if_fail(size != 0, -1);
442
443         session->state = SESSION_SEND;
444
445         session->write_data = data;
446         session->write_data_p = session->write_data;
447         session->write_data_len = size;
448         g_get_current_time(&session->tv_prev);
449
450         ret = session_write_data_cb(session->sock, G_IO_OUT, session);
451
452         if (ret == TRUE)
453                 session->io_tag = sock_add_watch(session->sock, G_IO_OUT,
454                                                  session_write_data_cb,
455                                                  session);
456         else if (session->state == SESSION_ERROR)
457                 return -1;
458
459         return 0;
460 }
461
462 gint session_recv_data(Session *session, guint size, const gchar *terminator)
463 {
464         g_return_val_if_fail(session->read_data_buf->len == 0, -1);
465
466         session->state = SESSION_RECV;
467
468         g_free(session->read_data_terminator);
469         session->read_data_terminator = g_strdup(terminator);
470         g_get_current_time(&session->tv_prev);
471
472         if (session->read_buf_len > 0)
473                 g_idle_add(session_recv_data_idle_cb, session);
474         else
475                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
476                                                  session_read_data_cb, session);
477
478         return 0;
479 }
480
481 static gboolean session_recv_data_idle_cb(gpointer data)
482 {
483         Session *session = SESSION(data);
484         gboolean ret;
485
486         ret = session_read_data_cb(session->sock, G_IO_IN, session);
487
488         if (ret == TRUE)
489                 session->io_tag = sock_add_watch(session->sock, G_IO_IN,
490                                                  session_read_data_cb, session);
491
492         return FALSE;
493 }
494
495 static gboolean session_read_msg_cb(SockInfo *source, GIOCondition condition,
496                                     gpointer data)
497 {
498         Session *session = SESSION(data);
499         gchar buf[SESSION_BUFFSIZE];
500         gint line_len;
501         gchar *newline;
502         gchar *msg;
503         gint ret;
504
505         g_return_val_if_fail(condition == G_IO_IN, FALSE);
506
507         session_set_timeout(session, session->timeout_interval);
508
509         if (session->read_buf_len == 0) {
510                 gint read_len;
511
512                 read_len = sock_read(session->sock, session->read_buf,
513                                      SESSION_BUFFSIZE - 1);
514
515                 if (read_len == -1 && session->state == SESSION_DISCONNECTED) {
516                         g_warning ("sock_read: session disconnected\n");
517                         if (session->io_tag > 0) {
518                                 g_source_remove(session->io_tag);
519                                 session->io_tag = 0;
520                         }
521                         return FALSE;
522                 }
523                 
524                 if (read_len == 0) {
525                         g_warning("sock_read: received EOF\n");
526                         session->state = SESSION_EOF;
527                         return FALSE;
528                 }
529
530                 if (read_len < 0) {
531                         switch (errno) {
532                         case EAGAIN:
533                                 return TRUE;
534                         default:
535                                 g_warning("sock_read: %s\n", g_strerror(errno));
536                                 session->state = SESSION_ERROR;
537                                 return FALSE;
538                         }
539                 }
540
541                 session->read_buf_len = read_len;
542         }
543
544         if ((newline = memchr(session->read_buf_p, '\n', session->read_buf_len))
545                 != NULL)
546                 line_len = newline - session->read_buf_p + 1;
547         else
548                 line_len = session->read_buf_len;
549
550         if (line_len == 0)
551                 return TRUE;
552
553         memcpy(buf, session->read_buf_p, line_len);
554         buf[line_len] = '\0';
555
556         g_string_append(session->read_msg_buf, buf);
557
558         session->read_buf_len -= line_len;
559         if (session->read_buf_len == 0)
560                 session->read_buf_p = session->read_buf;
561         else
562                 session->read_buf_p += line_len;
563
564         /* incomplete read */
565         if (buf[line_len - 1] != '\n')
566                 return TRUE;
567
568         /* complete */
569         if (session->io_tag > 0) {
570                 g_source_remove(session->io_tag);
571                 session->io_tag = 0;
572         }
573
574         /* callback */
575         msg = g_strdup(session->read_msg_buf->str);
576         strretchomp(msg);
577         g_string_truncate(session->read_msg_buf, 0);
578
579         ret = session->recv_msg(session, msg);
580         session->recv_msg_notify(session, msg, session->recv_msg_notify_data);
581
582         g_free(msg);
583
584         if (ret < 0)
585                 session->state = SESSION_ERROR;
586
587         return FALSE;
588 }
589
590 static gboolean session_read_data_cb(SockInfo *source, GIOCondition condition,
591                                      gpointer data)
592 {
593         Session *session = SESSION(data);
594         GByteArray *data_buf;
595         gint terminator_len;
596         gboolean complete = FALSE;
597         guint data_len;
598         gint ret;
599
600         g_return_val_if_fail(condition == G_IO_IN, FALSE);
601
602         session_set_timeout(session, session->timeout_interval);
603
604         if (session->read_buf_len == 0) {
605                 gint read_len;
606
607                 read_len = sock_read(session->sock, session->read_buf,
608                                      SESSION_BUFFSIZE);
609
610                 if (read_len == 0) {
611                         g_warning("sock_read: received EOF\n");
612                         session->state = SESSION_EOF;
613                         return FALSE;
614                 }
615
616                 if (read_len < 0) {
617                         switch (errno) {
618                         case EAGAIN:
619                                 return TRUE;
620                         default:
621                                 g_warning("sock_read: %s\n", g_strerror(errno));
622                                 session->state = SESSION_ERROR;
623                                 return FALSE;
624                         }
625                 }
626
627                 session->read_buf_len = read_len;
628         }
629
630         data_buf = session->read_data_buf;
631         terminator_len = strlen(session->read_data_terminator);
632
633         if (session->read_buf_len == 0)
634                 return TRUE;
635
636         g_byte_array_append(data_buf, session->read_buf_p,
637                             session->read_buf_len);
638
639         session->read_buf_len = 0;
640         session->read_buf_p = session->read_buf;
641
642         /* check if data is terminated */
643         if (data_buf->len >= terminator_len) {
644                 if (memcmp(data_buf->data, session->read_data_terminator,
645                            terminator_len) == 0)
646                         complete = TRUE;
647                 else if (data_buf->len >= terminator_len + 2 &&
648                          memcmp(data_buf->data + data_buf->len -
649                                 (terminator_len + 2), "\r\n", 2) == 0 &&
650                          memcmp(data_buf->data + data_buf->len -
651                                 terminator_len, session->read_data_terminator,
652                                 terminator_len) == 0)
653                         complete = TRUE;
654         }
655
656         /* incomplete read */
657         if (!complete) {
658                 GTimeVal tv_cur;
659
660                 g_get_current_time(&tv_cur);
661                 if (tv_cur.tv_sec - session->tv_prev.tv_sec > 0 ||
662                     tv_cur.tv_usec - session->tv_prev.tv_usec >
663                     UI_REFRESH_INTERVAL) {
664                         session->recv_data_progressive_notify
665                                 (session, data_buf->len, 0,
666                                  session->recv_data_progressive_notify_data);
667                         g_get_current_time(&session->tv_prev);
668                 }
669                 return TRUE;
670         }
671
672         /* complete */
673         if (session->io_tag > 0) {
674                 g_source_remove(session->io_tag);
675                 session->io_tag = 0;
676         }
677
678         data_len = data_buf->len - terminator_len;
679
680         /* callback */
681         ret = session->recv_data_finished(session, (gchar *)data_buf->data,
682                                           data_len);
683
684         g_byte_array_set_size(data_buf, 0);
685
686         session->recv_data_notify(session, data_len,
687                                   session->recv_data_notify_data);
688
689         if (ret < 0)
690                 session->state = SESSION_ERROR;
691
692         return FALSE;
693 }
694
695 static gint session_write_buf(Session *session)
696 {
697         gint write_len;
698         gint to_write_len;
699
700         g_return_val_if_fail(session->write_buf != NULL, -1);
701         g_return_val_if_fail(session->write_buf_p != NULL, -1);
702         g_return_val_if_fail(session->write_buf_len > 0, -1);
703
704         to_write_len = session->write_buf_len -
705                 (session->write_buf_p - session->write_buf);
706         to_write_len = MIN(to_write_len, SESSION_BUFFSIZE);
707
708         write_len = sock_write(session->sock, session->write_buf_p,
709                                to_write_len);
710
711         if (write_len < 0) {
712                 switch (errno) {
713                 case EAGAIN:
714                         write_len = 0;
715                         break;
716                 default:
717                         g_warning("sock_write: %s\n", g_strerror(errno));
718                         session->state = SESSION_ERROR;
719                         return -1;
720                 }
721         }
722
723         /* incomplete write */
724         if (session->write_buf_p - session->write_buf + write_len <
725             session->write_buf_len) {
726                 session->write_buf_p += write_len;
727                 return 1;
728         }
729
730         g_free(session->write_buf);
731         session->write_buf = NULL;
732         session->write_buf_p = NULL;
733         session->write_buf_len = 0;
734
735         return 0;
736 }
737
738 static gint session_write_data(Session *session)
739 {
740         gint write_len;
741         gint to_write_len;
742
743         g_return_val_if_fail(session->write_data != NULL, -1);
744         g_return_val_if_fail(session->write_data_p != NULL, -1);
745         g_return_val_if_fail(session->write_data_len > 0, -1);
746
747         to_write_len = session->write_data_len -
748                 (session->write_data_p - session->write_data);
749         to_write_len = MIN(to_write_len, SESSION_BUFFSIZE);
750
751         write_len = sock_write(session->sock, session->write_data_p,
752                                to_write_len);
753
754         if (write_len < 0) {
755                 switch (errno) {
756                 case EAGAIN:
757                         write_len = 0;
758                         break;
759                 default:
760                         g_warning("sock_write: %s\n", g_strerror(errno));
761                         session->state = SESSION_ERROR;
762                         return -1;
763                 }
764         }
765
766         /* incomplete write */
767         if (session->write_data_p - session->write_data + write_len <
768             session->write_data_len) {
769                 session->write_data_p += write_len;
770                 return 1;
771         }
772
773         session->write_data = NULL;
774         session->write_data_p = NULL;
775         session->write_data_len = 0;
776
777         return 0;
778 }
779
780 static gboolean session_write_msg_cb(SockInfo *source, GIOCondition condition,
781                                      gpointer data)
782 {
783         Session *session = SESSION(data);
784         gint ret;
785
786         g_return_val_if_fail(condition == G_IO_OUT, FALSE);
787         g_return_val_if_fail(session->write_buf != NULL, FALSE);
788         g_return_val_if_fail(session->write_buf_p != NULL, FALSE);
789         g_return_val_if_fail(session->write_buf_len > 0, FALSE);
790
791         ret = session_write_buf(session);
792
793         if (ret < 0) {
794                 session->state = SESSION_ERROR;
795                 return FALSE;
796         } else if (ret > 0)
797                 return TRUE;
798
799         if (session->io_tag > 0) {
800                 g_source_remove(session->io_tag);
801                 session->io_tag = 0;
802         }
803
804         session_recv_msg(session);
805
806         return FALSE;
807 }
808
809 static gboolean session_write_data_cb(SockInfo *source,
810                                       GIOCondition condition, gpointer data)
811 {
812         Session *session = SESSION(data);
813         guint write_data_len;
814         gint ret;
815
816         g_return_val_if_fail(condition == G_IO_OUT, FALSE);
817         g_return_val_if_fail(session->write_data != NULL, FALSE);
818         g_return_val_if_fail(session->write_data_p != NULL, FALSE);
819         g_return_val_if_fail(session->write_data_len > 0, FALSE);
820
821         write_data_len = session->write_data_len;
822
823         ret = session_write_data(session);
824
825         if (ret < 0) {
826                 session->state = SESSION_ERROR;
827                 return FALSE;
828         } else if (ret > 0) {
829                 GTimeVal tv_cur;
830
831                 g_get_current_time(&tv_cur);
832                 if (tv_cur.tv_sec - session->tv_prev.tv_sec > 0 ||
833                     tv_cur.tv_usec - session->tv_prev.tv_usec >
834                     UI_REFRESH_INTERVAL) {
835                         session_set_timeout(session, session->timeout_interval);
836                         session->send_data_progressive_notify
837                                 (session,
838                                  session->write_data_p - session->write_data,
839                                  write_data_len,
840                                  session->send_data_progressive_notify_data);
841                         g_get_current_time(&session->tv_prev);
842                 }
843                 return TRUE;
844         }
845
846         if (session->io_tag > 0) {
847                 g_source_remove(session->io_tag);
848                 session->io_tag = 0;
849         }
850
851         /* callback */
852         ret = session->send_data_finished(session, write_data_len);
853         session->send_data_notify(session, write_data_len,
854                                   session->send_data_notify_data);
855
856         return FALSE;
857 }