* src/common/session.c
[claws.git] / src / common / session.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2003 Hiroyuki Yamamoto
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 2 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <sys/signal.h>
34 #include <sys/wait.h>
35 #include <sys/time.h>
36
37 #include "session.h"
38 #include "utils.h"
39
40 static gint session_close               (Session        *session);
41
42 static gchar *session_recv_msg          (Session        *session);
43
44 static guchar *session_read_data        (Session        *session,
45                                          guint           size);
46
47 static gint session_send_data_to_sock           (Session        *session,
48                                                  const guchar   *data,
49                                                  guint           size);
50 static guchar *session_recv_data_from_sock      (Session        *session,
51                                                  guint           size);
52
53 static guchar *session_recv_data_from_sock_unescape     (Session *session,
54                                                          guint    size,
55                                                          guint   *actual_size);
56
57 gboolean session_parent_input_cb        (GIOChannel     *source,
58                                          GIOCondition    condition,
59                                          gpointer        data);
60
61 gboolean session_child_input            (Session        *session);
62
63
64 /*!
65  *\brief        init session members to zero
66  *
67  *\param        session to be initialized
68  */
69 void session_init(Session *session)
70 {
71         session->type = 0;
72         session->sock = NULL;
73
74         session->server = NULL;
75         session->port = 0;
76         session->state = SESSION_READY;
77         session->last_access_time = time(NULL);
78         session->data = NULL;
79
80         session->read_ch = NULL;
81         session->write_ch = NULL;
82 }
83
84 /*!
85  *\brief        Set up parent and child process
86  *              Childloop: Read commands from parent,
87  *              send to server, get answer, pass to parent
88  *
89  *\param        session Contains session information
90  *              server to connect to
91  *              port to connect to
92  *
93  *\return        0 : success
94  *              -1 : pipe / fork errors (parent)
95  *               1 : connection error (child)
96  */
97 gint session_connect(Session *session, const gchar *server, gushort port)
98 {
99         pid_t pid;
100         gint pipe_fds1[2], pipe_fds2[2];
101         SockInfo *sock;
102         gchar *str;
103
104         session->server = g_strdup(server);
105         session->port = port;
106
107         if (pipe(pipe_fds1) < 0) {
108                 perror("pipe");
109                 return -1;
110         }
111         if (pipe(pipe_fds2) < 0) {
112                 perror("pipe");
113                 close(pipe_fds1[0]);
114                 close(pipe_fds1[1]);
115                 return -1;
116         }
117
118         if ((pid = fork()) < 0) {
119                 perror("fork");
120                 return -1;
121         }
122
123         if (pid != 0) {
124                 session->child_pid = pid;
125                 session->read_ch = g_io_channel_unix_new(pipe_fds2[0]);
126                 session->write_ch = g_io_channel_unix_new(pipe_fds1[1]);
127                 close(pipe_fds1[0]);
128                 close(pipe_fds2[1]);
129                 session->read_tag = g_io_add_watch(session->read_ch, G_IO_IN,
130                                                    session_parent_input_cb,
131                                                    session);
132                 return 0;
133         }
134
135         /* child process */
136
137         session->read_ch = g_io_channel_unix_new(pipe_fds1[0]);
138         session->write_ch = g_io_channel_unix_new(pipe_fds2[1]);
139         close(pipe_fds1[1]);
140         close(pipe_fds2[0]);
141
142         debug_print("session: child: connecting to %s:%d ...\n", server, port);
143
144         if ((sock = sock_connect(server, port)) == NULL) {
145                 session_send_msg(session, SESSION_MSG_ERROR,
146                                  "can't connect to server.");
147                 session_close(session);
148                 _exit(1);
149         }
150
151 #if USE_OPENSSL
152         if (session->ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
153                 session_send_msg(session, SESSION_MSG_ERROR,
154                                  "can't initialize SSL.");
155                 session_close(session);
156                 _exit(1);
157         }
158 #endif
159
160         debug_print("session: child: connected\n");
161
162         session->sock = sock;
163         session->state = SESSION_RECV;
164
165         if ((str = sock_getline(sock)) == NULL) {
166                 session_send_msg(session, SESSION_MSG_ERROR,
167                                  "can't get server response.");
168                 session_close(session);
169                 _exit(1);
170         }
171         strretchomp(str);
172         session_send_msg(session, SESSION_MSG_NORMAL, str);
173         g_free(str);
174
175         while (session_child_input(session) == TRUE)
176                 ;
177
178         session_close(session);
179
180         debug_print("session: child: disconnected\n");
181
182         _exit(0);
183 }
184
185 /*!
186  *\brief        child and parent: send DISCONNECT message to other process
187  *
188  *\param        session Contains session information
189  *
190  *\return        0 : success
191  */
192 gint session_disconnect(Session *session)
193 {
194         debug_print("session: %s: session_disconnect()\n",
195                     session->child_pid == 0 ? "child" : "parent");
196         session_send_msg(session, SESSION_MSG_CONTROL, "DISCONNECT");
197         return 0;
198 }
199
200 /*!
201  *\brief        parent ?
202  *
203  *\param        session Contains session information
204  */
205 void session_destroy(Session *session)
206 {
207         g_return_if_fail(session != NULL);
208         g_return_if_fail(session->destroy != NULL);
209
210         debug_print("session: session_destroy()\n");
211         session_close(session);
212         session->destroy(session);
213         g_free(session->server);
214         g_free(session);
215 }
216
217 void session_set_recv_message_notify(Session *session,
218                                      RecvMsgNotify notify_func, gpointer data)
219 {
220         session->recv_msg_notify = notify_func;
221         session->recv_msg_notify_data = data;
222 }
223
224 void session_set_recv_data_progressive_notify
225                                         (Session *session,
226                                          RecvDataProgressiveNotify notify_func,
227                                          gpointer data)
228 {
229         session->recv_data_progressive_notify = notify_func,
230         session->recv_data_progressive_notify_data = data;
231 }
232
233 void session_set_recv_data_notify(Session *session, RecvDataNotify notify_func,
234                                   gpointer data)
235 {
236         session->recv_data_notify = notify_func;
237         session->recv_data_notify_data = data;
238 }
239
240 void session_set_send_data_progressive_notify
241                                         (Session *session,
242                                          SendDataProgressiveNotify notify_func,
243                                          gpointer data)
244 {
245         session->send_data_progressive_notify = notify_func;
246         session->send_data_progressive_notify_data = data;
247 }
248
249 void session_set_send_data_notify(Session *session, SendDataNotify notify_func,
250                                   gpointer data)
251 {
252         session->send_data_notify = notify_func;
253         session->send_data_notify_data = data;
254 }
255
256 /*!
257  *\brief        child and parent cleanup (child closes first)
258  *
259  *\param        session Contains session information
260  *
261  *\return        0 : success
262  */
263 static gint session_close(Session *session)
264 {
265         g_return_val_if_fail(session != NULL, -1);
266
267         debug_print("session: %s: session_close()\n",
268                     session->child_pid == 0 ? "child" : "parent");
269
270         if (session->read_tag > 0) {
271                 g_source_remove(session->read_tag);
272                 session->read_tag = 0;
273         }
274         
275         if (session->read_ch) {
276                 g_io_channel_close(session->read_ch);
277                 g_io_channel_unref(session->read_ch);
278                 session->read_ch = NULL;
279         }
280         
281         if (session->write_ch) {
282                 g_io_channel_close(session->write_ch);
283                 g_io_channel_unref(session->write_ch);
284                 session->write_ch = NULL;
285         }
286
287         if (session->sock) {
288                 sock_close(session->sock);
289                 session->sock = NULL;
290                 session->state = SESSION_DISCONNECTED;
291         }
292
293         if (session->child_pid) {
294                 if (session->state != SESSION_DISCONNECTED)
295                         kill(session->child_pid, SIGTERM);
296                 waitpid(session->child_pid, NULL, 0);
297                 session->child_pid = 0;
298         }
299
300         return 0;
301 }
302
303 /*!
304  *\brief        child and parent: send control message to other process
305  *
306  *\param        session Contains session information
307  *              type Kind of data (commands or message data)
308  *              msg Data
309  *
310  *\return        0 : success
311  *              -1 : error
312  */
313 gint session_send_msg(Session *session, SessionMsgType type, const gchar *msg)
314 {
315         gchar *prefix;
316         gchar *str;
317         gchar *cur;
318         guint size;
319         guint bytes_written;
320
321         switch (type) {
322         case SESSION_MSG_NORMAL:
323                 prefix = "MESSAGE"; break;
324         case SESSION_MSG_SEND_DATA:
325                 prefix = "SENDDATA"; break;
326         case SESSION_MSG_RECV_DATA:
327                 prefix = "RECVDATA"; break;
328         case SESSION_MSG_CONTROL:
329                 prefix = "CONTROL"; break;
330         case SESSION_MSG_ERROR:
331                 prefix = "ERROR"; break;
332         default:
333                 return -1;
334         }
335
336         cur = str = g_strdup_printf("%s %s\n", prefix, msg);
337         size = strlen(str);
338
339         while (size > 0) {
340                 if (g_io_channel_write(session->write_ch, cur, size,
341                                        &bytes_written)
342                     != G_IO_ERROR_NONE || bytes_written == 0) {
343                         g_warning("%s: sending message failed.\n",
344                                   session->child_pid == 0 ? "child" : "parent");
345                         g_free(str);
346                         return -1;
347                 }
348                 size -= bytes_written;
349                 cur += bytes_written;
350         }
351
352         g_free(str);
353
354         return 0;
355 }
356
357 /*!
358  *\brief        child and parent receive function
359  *
360  *\param        session Contains session information
361  *
362  *\return       Message read by current session
363  */
364 static gchar *session_recv_msg(Session *session)
365 {
366         gchar buf[BUFFSIZE];
367         gchar *str = NULL;
368         guint size = 1;
369         guint bytes_read;
370
371         for (;;) {
372                 if (g_io_channel_read(session->read_ch, buf, sizeof(buf) - 1,
373                                       &bytes_read)
374                     != G_IO_ERROR_NONE || bytes_read == 0) {
375                         g_warning("%s: receiving message failed.\n",
376                                   session->child_pid == 0 ? "child" : "parent");
377                         g_free(str);
378                         str = NULL;
379                         break;
380                 }
381
382                 size += bytes_read;
383                 buf[bytes_read] = '\0';
384
385                 if (!str)
386                         str = g_strdup(buf);
387                 else {
388                         str = g_realloc(str, size);
389                         strcat(str, buf);
390                 }
391                 if (str[size - 2] == '\n') {
392                         str[size - 2] = '\0';
393
394                         debug_print("session: %s: received message: %s\n",
395                                     session->child_pid == 0 ?
396                                     "child" : "parent", str);
397
398                         break;
399                 }
400         }
401
402         return str;
403 }
404
405 #if USE_OPENSSL
406 gint session_start_tls(Session *session)
407 {
408         gchar *ctl_msg;
409
410         session_send_msg(session, SESSION_MSG_CONTROL, "STARTTLS");
411         ctl_msg = session_recv_msg(session);
412         if (!ctl_msg || strcmp(ctl_msg, "CONTROL STARTTLSOK") != 0) {
413                 g_free(ctl_msg);
414                 return -1;
415         }
416         g_free(ctl_msg);
417
418         return 0;
419 }
420 #endif
421
422 /*!
423  *\brief        parent (child?): send data to other process
424  *
425  *\param        session Contains session information
426  *              data Data to send
427  *              size Bytes to send
428  *
429  *\return        0 : success
430  *              -1 : error
431  */
432 gint session_send_data(Session *session, const guchar *data, guint size)
433 {
434         gchar *msg;
435         const guchar *cur = data;
436         guint bytes_written;
437         GIOError err;
438
439         session_send_msg(session, SESSION_MSG_SEND_DATA, itos(size));
440         if ((msg = session_recv_msg(session)) == NULL)
441                 return -1;
442         g_free(msg);
443
444         while (size > 0) {
445                 if ((err = g_io_channel_write(session->write_ch, (guchar *)cur,
446                                               size, &bytes_written))
447                     != G_IO_ERROR_NONE || bytes_written == 0) {
448                         g_warning("%s: sending data failed: %d\n",
449                                   session->child_pid == 0 ? "child" : "parent",
450                                   err);
451                         return -1;
452                 }
453                 size -= bytes_written;
454                 cur += bytes_written;
455                 debug_print("session: %s: sent %d bytes of data\n",
456                             session->child_pid == 0 ? "child" : "parent",
457                             bytes_written);
458         }
459
460         return 0;
461 }
462
463 gint session_recv_data(Session *session, guint size, gboolean unescape_dot)
464 {
465         if (unescape_dot) {
466                 gchar buf[BUFFSIZE];
467
468                 g_snprintf(buf, sizeof(buf), "%d UNESCAPE", size);
469                 session_send_msg(session, SESSION_MSG_RECV_DATA, buf);
470         } else
471                 session_send_msg(session, SESSION_MSG_RECV_DATA, itos(size));
472         return 0;
473 }
474
475 /*!
476  *\brief        child (parent?): read data from other process
477  *
478  *\param        session Contains session information
479  *              size Bytes to read
480  *
481  *\return       data read from session
482  */
483 static guchar *session_read_data(Session *session, guint size)
484 {
485         guchar *data;
486         guchar *cur;
487         guint bytes_read;
488         GIOError err;
489
490         cur = data = g_malloc(size);
491
492         while (size > 0) {
493                 if ((err = g_io_channel_read(session->read_ch, cur, size,
494                                              &bytes_read))
495                     != G_IO_ERROR_NONE || bytes_read == 0) {
496                         g_warning("%s: reading data failed: %d\n",
497                                   session->child_pid == 0 ? "child" : "parent",
498                                   err);
499                         g_free(data);
500                         return NULL;
501                 }
502                 size -= bytes_read;
503                 cur += bytes_read;
504                 debug_print("session: %s: received %d bytes of data\n",
505                             session->child_pid == 0 ? "child" : "parent",
506                             bytes_read);
507         }
508
509         return data;
510 }
511
512 #define MAX_CHUNK_SIZE 4096
513
514 /*!
515  *\brief        child: Send session data to server
516  *
517  *\param        session Contains session information
518  *              data Data to send to server
519  *              size Bytes to send
520  *
521  *\return        0 : success
522  *              -1 : error
523  */
524 static gint session_send_data_to_sock(Session *session, const guchar *data,
525                                       guint size)
526 {
527         const guchar *cur = data;
528         gint bytes_written;
529         gint total_write_len = 0;
530         guint left = size;
531         gchar buf[BUFFSIZE];
532         gchar *msg;
533         struct timeval tv_prev, tv_cur;
534
535         gettimeofday(&tv_prev, NULL);
536
537         while (1) {
538                 bytes_written = sock_write(session->sock, cur,
539                                            MIN(left, MAX_CHUNK_SIZE));
540                 if (bytes_written <= 0)
541                         return -1;
542                 left -= bytes_written;
543                 cur += bytes_written;
544                 total_write_len += bytes_written;
545                 if (left == 0)
546                         break;
547
548                 gettimeofday(&tv_cur, NULL);
549                 if (tv_cur.tv_sec - tv_prev.tv_sec > 0 ||
550                     tv_cur.tv_usec - tv_prev.tv_usec > UI_REFRESH_INTERVAL) {
551                         g_snprintf(buf, sizeof(buf), "DATASENDINPROG %d %d",
552                                    total_write_len, size);
553                         session_send_msg(session, SESSION_MSG_CONTROL, buf);
554                         if ((msg = session_recv_msg(session)) == NULL)
555                                 return -1;
556                         g_free(msg);
557                         gettimeofday(&tv_prev, NULL);
558                 }
559         }
560
561         return 0;
562 }
563
564 /*!
565  *\brief        child: Read answer/data from server
566  *
567  *\param        session Contains session information
568  *              size Max bytes to receive
569  *
570  *\return       Server answer
571  */
572 static guchar *session_recv_data_from_sock(Session *session, guint size)
573 {
574         guchar *data;
575         guchar *cur;
576         gint bytes_read;
577         gint total_read_len = 0;
578         guint left = size;
579         gchar buf[BUFFSIZE];
580         gchar *msg;
581         struct timeval tv_prev, tv_cur;
582
583         gettimeofday(&tv_prev, NULL);
584
585         cur = data = g_malloc(size);
586
587         while (1) {
588                 bytes_read = sock_read(session->sock, cur, left);
589                 if (bytes_read <= 0) {
590                         g_free(data);
591                         return NULL;
592                 }
593                 debug_print("session: child: "
594                             "received %d bytes of data from sock\n",
595                             bytes_read);
596                 left -= bytes_read;
597                 cur += bytes_read;
598                 total_read_len += bytes_read;
599                 if (left == 0)
600                         break;
601
602                 gettimeofday(&tv_cur, NULL);
603                 if (tv_cur.tv_sec - tv_prev.tv_sec > 0 ||
604                     tv_cur.tv_usec - tv_prev.tv_usec > UI_REFRESH_INTERVAL) {
605                         g_snprintf(buf, sizeof(buf), "DATARECVINPROG %d %d",
606                                    total_read_len, size);
607                         session_send_msg(session, SESSION_MSG_CONTROL, buf);
608                         if ((msg = session_recv_msg(session)) == NULL) {
609                                 g_free(data);
610                                 return NULL;
611                         }
612                         g_free(msg);
613                         gettimeofday(&tv_prev, NULL);
614                 }
615         }
616
617         return data;
618 }
619
620 static guchar *session_recv_data_from_sock_unescape(Session *session,
621                                                     guint size,
622                                                     guint *actual_size)
623 {
624         GString *data;
625         guchar *ret_data;
626         gint bytes_read;
627         gchar buf[BUFFSIZE];
628         gchar *msg;
629         struct timeval tv_prev, tv_cur;
630
631         gettimeofday(&tv_prev, NULL);
632
633         data = g_string_sized_new(size + 1);
634         *actual_size = 0;
635
636         while (1) {
637                 bytes_read = sock_gets(session->sock, buf, sizeof(buf));
638                 if (bytes_read <= 0) {
639                         g_string_free(data, TRUE);
640                         return NULL;
641                 }
642
643                 if (buf[0] == '.' && buf[1] == '\r' && buf[2] == '\n')
644                         break;
645                 if (buf[0] == '.' && buf[1] == '.')
646                         g_string_append(data, buf + 1);
647                 else
648                         g_string_append(data, buf);
649
650                 gettimeofday(&tv_cur, NULL);
651                 if (tv_cur.tv_sec - tv_prev.tv_sec > 0 ||
652                     tv_cur.tv_usec - tv_prev.tv_usec > UI_REFRESH_INTERVAL) {
653                         g_snprintf(buf, sizeof(buf), "DATARECVINPROG %d %d",
654                                    data->len, MAX(data->len, size));
655                         session_send_msg(session, SESSION_MSG_CONTROL, buf);
656                         if ((msg = session_recv_msg(session)) == NULL) {
657                                 g_string_free(data, TRUE);
658                                 return NULL;
659                         }
660                         g_free(msg);
661                         gettimeofday(&tv_prev, NULL);
662                 }
663         }
664
665         ret_data = data->str;
666         *actual_size = data->len;
667         g_string_free(data, FALSE);
668
669         return ret_data;
670 }
671
672 /*!
673  *\brief        Return if message is an internal command or server data
674  *
675  *\param        str Message to analyze
676  *
677  *\return       Type of message
678  */
679 static SessionMsgType session_get_msg_type(const gchar *str)
680 {
681         if (!strncmp(str, "MESSAGE ", 8))
682                 return SESSION_MSG_NORMAL;
683         else if (!strncmp(str, "SENDDATA ", 9))
684                 return SESSION_MSG_SEND_DATA;
685         else if (!strncmp(str, "RECVDATA ", 9))
686                 return SESSION_MSG_RECV_DATA;
687         else if (!strncmp(str, "CONTROL ", 8))
688                 return SESSION_MSG_CONTROL;
689         else if (!strncmp(str, "ERROR ", 6))
690                 return SESSION_MSG_ERROR;
691         else
692                 return SESSION_MSG_UNKNOWN;
693 }
694
695 /*!
696  *\brief        parent: Received data from child
697  *
698  *\param        source Channel watching child pipe
699  *              condition Unused (IN, HUP, OUT)
700  *              data Contains session information
701  *
702  *\return       FALSE to remove watching channel
703  */
704 gboolean session_parent_input_cb(GIOChannel *source, GIOCondition condition,
705                                  gpointer data)
706 {
707         Session *session = SESSION(data);
708         gchar *msg;
709         gchar *msg_data;
710         gint len;
711         gint total;
712         guchar *recv_data;
713         guint size;
714         gint ret;
715
716         if ((msg = session_recv_msg(session)) == NULL) {
717                 session->state = SESSION_ERROR;
718                 return FALSE;
719         }
720
721         switch (session_get_msg_type(msg)) {
722         case SESSION_MSG_NORMAL:
723                 msg_data = msg + strlen("MESSAGE ");
724                 ret = session->recv_msg(session, msg_data);
725                 session->recv_msg_notify(session, msg_data,
726                                          session->recv_msg_notify_data);
727                 if (ret > 0)
728                         session_send_msg(session, SESSION_MSG_CONTROL,
729                                          "CONTINUE");
730                 else if (ret < 0) {
731                         session->state = SESSION_ERROR;
732                         g_free(msg);
733                         return FALSE;
734                 }
735                 break;
736         case SESSION_MSG_SEND_DATA:
737                 msg_data = msg + strlen("SENDDATA ");
738                 size = atoi(msg_data);
739                 session_send_msg(session, SESSION_MSG_CONTROL, "ACCEPTDATA");
740                 recv_data = session_read_data(session, size);
741                 if (!recv_data) {
742                         session->state = SESSION_ERROR;
743                         g_free(msg);
744                         return FALSE;
745                 }
746                 ret = session->recv_data_finished(session, recv_data, size);
747                 g_free(recv_data);
748                 session->recv_data_notify(session, size,
749                                           session->recv_data_notify_data);
750                 if (ret > 0)
751                         session_send_msg(session, SESSION_MSG_CONTROL,
752                                          "CONTINUE");
753                 else if (ret < 0) {
754                         session->state = SESSION_ERROR;
755                         g_free(msg);
756                         return FALSE;
757                 }
758                 break;
759         case SESSION_MSG_RECV_DATA:
760                 break;
761         case SESSION_MSG_CONTROL:
762                 msg_data = msg + strlen("CONTROL ");
763                 if (!strncmp(msg_data, "DATARECVINPROG ", 15)) {
764                         ret = sscanf(msg_data,
765                                      "DATARECVINPROG %d %d", &len, &total);
766                         if (ret != 2) {
767                                 g_warning("wrong control message: %s\n", msg);
768                                 session->state = SESSION_ERROR;
769                                 g_free(msg);
770                                 return FALSE;
771                         }
772                         session_send_msg(session, SESSION_MSG_CONTROL,
773                                          "CONTINUE");
774                         session->recv_data_progressive_notify
775                                 (session, len, total,
776                                  session->recv_data_progressive_notify_data);
777                 } else if (!strncmp(msg_data, "DATASENDINPROG ", 15)) {
778                         ret = sscanf(msg_data,
779                                      "DATASENDINPROG %d %d", &len, &total);
780                         if (ret != 2) {
781                                 g_warning("wrong control message: %s\n", msg);
782                                 session->state = SESSION_ERROR;
783                                 g_free(msg);
784                                 return FALSE;
785                         }
786                         session_send_msg(session, SESSION_MSG_CONTROL,
787                                          "CONTINUE");
788                         session->send_data_progressive_notify
789                                 (session, len, total,
790                                  session->send_data_progressive_notify_data);
791                 } else if (!strncmp(msg_data, "DATASENT ", 9)) {
792                         len = atoi(msg_data + 9);
793                         ret = session->send_data_finished(session, len);
794                         session->send_data_notify
795                                 (session, len, session->send_data_notify_data);
796                 } else if (!strcmp(msg_data, "DISCONNECTED")) {
797                         session->state = SESSION_DISCONNECTED;
798                         g_free(msg);
799                         return FALSE;
800                 } else {
801                         g_warning("wrong control message: %s\n", msg);
802                         session->state = SESSION_ERROR;
803                         g_free(msg);
804                         return FALSE;
805                 }
806                 break;
807         case SESSION_MSG_ERROR:
808         default:
809                 g_warning("error from child: %s\n", msg + strlen("ERROR "));
810                 session->state = SESSION_ERROR;
811                 g_free(msg);
812                 return FALSE;
813         }
814
815         g_free(msg);
816         return TRUE;
817 }
818
819 /*!
820  *\brief        child: Receive control message from parent,
821  *              transfer data from/to server
822  *
823  *\param        session Contains session information
824  *
825  *\return       TRUE if more data is available
826  */
827 gboolean session_child_input(Session *session)
828 {
829         gchar buf[BUFFSIZE];
830         gchar *msg;
831         gchar *msg_data;
832         gchar *str;
833         guchar *send_data;
834         guchar *recv_data;
835         guint size;
836         guint actual_size;
837
838         if ((msg = session_recv_msg(session)) == NULL) {
839                 session_send_msg(session, SESSION_MSG_ERROR,
840                                  "receiving message failed.");
841                 session->state = SESSION_ERROR;
842                 return FALSE;
843         }
844
845         switch (session_get_msg_type(msg)) {
846         case SESSION_MSG_NORMAL:
847                 msg_data = msg + strlen("MESSAGE ");
848                 session->state = SESSION_SEND;
849                 sock_puts(session->sock, msg_data);
850                 session->state = SESSION_RECV;
851                 str = sock_getline(session->sock);
852                 if (!str) {
853                         session_send_msg(session, SESSION_MSG_ERROR,
854                                          "receiving message failed.");
855                         session->state = SESSION_ERROR;
856                         g_free(msg);
857                         return FALSE;
858                 }
859                 strretchomp(str);
860                 session_send_msg(session, SESSION_MSG_NORMAL, str);
861                 g_free(str);
862                 break;
863         case SESSION_MSG_SEND_DATA:
864                 msg_data = msg + strlen("SENDDATA ");
865                 size = atoi(msg_data);
866                 session_send_msg(session, SESSION_MSG_CONTROL, "ACCEPTDATA");
867                 send_data = session_read_data(session, size);
868                 if (!send_data) {
869                         session_send_msg(session, SESSION_MSG_ERROR,
870                                          "sending data failed.");
871                         session->state = SESSION_ERROR;
872                         g_free(msg);
873                         return FALSE;
874                 }
875                 session->state = SESSION_SEND;
876                 if (session_send_data_to_sock(session, send_data, size) < 0) {
877                         session_send_msg(session, SESSION_MSG_ERROR,
878                                          "sending data failed.");
879                         session->state = SESSION_ERROR;
880                         g_free(send_data);
881                         g_free(msg);
882                         return FALSE;
883                 }
884                 g_free(send_data);
885                 g_snprintf(buf, sizeof(buf), "DATASENT %d", size);
886                 session_send_msg(session, SESSION_MSG_CONTROL, buf);
887                 break;
888         case SESSION_MSG_RECV_DATA:
889                 msg_data = msg + strlen("RECVDATA ");
890                 size = atoi(msg_data);
891                 session->state = SESSION_RECV;
892                 if (strstr(msg_data, "UNESCAPE") != NULL) {
893                         recv_data = session_recv_data_from_sock_unescape
894                                 (session, size, &actual_size);
895                         size = actual_size;
896                 } else
897                         recv_data = session_recv_data_from_sock(session, size);
898                 if (!recv_data) {
899                         session_send_msg(session, SESSION_MSG_ERROR,
900                                          "receiving data failed.");
901                         session->state = SESSION_ERROR;
902                         g_free(msg);
903                         return FALSE;
904                 }
905                 if (session_send_data(session, recv_data, size) < 0) {
906                         session->state = SESSION_ERROR;
907                         g_free(recv_data);
908                         g_free(msg);
909                         return FALSE;
910                 }
911                 g_free(recv_data);
912                 break;
913         case SESSION_MSG_CONTROL:
914                 msg_data = msg + strlen("CONTROL ");
915                 if (!strcmp(msg_data, "CONTINUE")) {
916                         session->state = SESSION_RECV;
917                         str = sock_getline(session->sock);
918                         if (!str) {
919                                 session_send_msg(session, SESSION_MSG_ERROR,
920                                                  "receiving message failed.");
921                                 session->state = SESSION_ERROR;
922                                 g_free(msg);
923                                 return FALSE;
924                         }
925                         strretchomp(str);
926                         session_send_msg(session, SESSION_MSG_NORMAL, str);
927                         g_free(str);
928                         break;
929 #if USE_OPENSSL
930                 } else if (!strcmp(msg_data, "STARTTLS")) {
931                         if (!ssl_init_socket_with_method(session->sock,
932                                                          SSL_METHOD_TLSv1)) {
933                                 session_send_msg(session, SESSION_MSG_ERROR,
934                                                  "can't start TLS session.");
935                                 session->state = SESSION_ERROR;
936                                 g_free(msg);
937                                 return FALSE;
938                         }
939                         session_send_msg(session, SESSION_MSG_CONTROL,
940                                          "STARTTLSOK");
941                         break;
942 #endif
943                 } else if (!strcmp(msg_data, "DISCONNECT")) {
944                         sock_close(session->sock);
945                         session->sock = NULL;
946                         session->state = SESSION_DISCONNECTED;
947                         session_send_msg(session, SESSION_MSG_CONTROL,
948                                          "DISCONNECTED");
949                         g_free(msg);
950                         return FALSE;
951                 } else {
952                         session_send_msg(session, SESSION_MSG_ERROR,
953                                          "wrong control message.");
954                         session->state = SESSION_ERROR;
955                         g_free(msg);
956                         return FALSE;
957                 }
958                 break;
959         case SESSION_MSG_ERROR:
960         default:
961                 session_send_msg(session, SESSION_MSG_ERROR,
962                                  "error received from parent.");
963                 session->state = SESSION_ERROR;
964                 g_free(msg);
965                 return FALSE;
966         }
967
968         g_free(msg);
969         return TRUE;
970 }