ba18107d76c1307c46ab7754c4c39796eb28dc02
[citadel.git] / citadel / event_client.c
1 /*
2  *
3  * Copyright (c) 1998-2009 by the citadel.org 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, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "sysdep.h"
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <termios.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <pwd.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <syslog.h>
31
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
34 # include <time.h>
35 #else
36 # if HAVE_SYS_TIME_H
37 #  include <sys/time.h>
38 # else
39 #  include <time.h>
40 # endif
41 #endif
42 #include <sys/wait.h>
43 #include <ctype.h>
44 #include <string.h>
45 #include <limits.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <libcitadel.h>
50 #include "citadel.h"
51 #include "server.h"
52 #include "citserver.h"
53 #include "support.h"
54 #include "config.h"
55 #include "control.h"
56 #include "user_ops.h"
57 #include "database.h"
58 #include "msgbase.h"
59 #include "internet_addressing.h"
60 #include "genstamp.h"
61 #include "domain.h"
62 #include "clientsocket.h"
63 #include "locate_host.h"
64 #include "citadel_dirs.h"
65
66 #ifdef EXPERIMENTAL_SMTP_EVENT_CLIENT
67
68 #include <event.h>
69 #include "event_client.h"
70
71 extern int event_add_pipe[2];
72 extern citthread_mutex_t EventQueueMutex;
73 extern void *QueueEventAddPtr;
74 extern AsyncIO *QueueThisIO;
75 extern EventContextAttach EventContextAttachPtr;
76
77 int QueueEventContext(void *Ctx, AsyncIO *IO, EventContextAttach CB)
78 {
79         citthread_mutex_lock(&EventQueueMutex);
80         if (event_add_pipe[1] == -1) {
81                 citthread_mutex_unlock(&EventQueueMutex);
82
83                 return -1;
84         }
85
86         QueueEventAddPtr = Ctx;
87         EventContextAttachPtr = CB;
88         QueueThisIO = IO;
89
90         write(event_add_pipe[1], "+_", 1);
91         citthread_mutex_unlock(&EventQueueMutex);
92         return 0;
93 }
94
95
96 int ShutDownEventQueue(void)
97 {
98         citthread_mutex_lock(&EventQueueMutex);
99         if (event_add_pipe[1] == -1) {
100                 citthread_mutex_unlock(&EventQueueMutex);
101
102                 return -1;
103         }
104         write(event_add_pipe[1], "x_", 1);
105         close(event_add_pipe[1]);
106         event_add_pipe[1] = -1;
107         citthread_mutex_unlock(&EventQueueMutex);
108         return 0;
109 }
110
111 void FreeAsyncIOContents(AsyncIO *IO)
112 {
113         FreeStrBuf(&IO->IOBuf);
114         FreeStrBuf(&IO->SendBuf.Buf);
115         FreeStrBuf(&IO->RecvBuf.Buf);
116
117 }
118
119 /*
120 static void
121 setup_signal_handlers(struct instance *instance)
122 {
123     signal(SIGPIPE, SIG_IGN);
124
125     event_set(&instance->sigterm_event, SIGTERM, EV_SIGNAL|EV_PERSIST,
126               exit_event_callback, instance);
127     event_add(&instance->sigterm_event, NULL);
128
129     event_set(&instance->sigint_event, SIGINT, EV_SIGNAL|EV_PERSIST,
130               exit_event_callback, instance);
131     event_add(&instance->sigint_event, NULL);
132
133     event_set(&instance->sigquit_event, SIGQUIT, EV_SIGNAL|EV_PERSIST,
134               exit_event_callback, instance);
135     event_add(&instance->sigquit_event, NULL);
136 }
137 */
138
139 void ShutDownCLient(AsyncIO *IO)
140 {
141         event_del(&IO->send_event);
142         event_del(&IO->recv_event);
143         IO->Terminate(IO->Data);
144
145 //      citthread_mutex_lock(&EventQueueMutex);
146
147 ///QueueEvents /// todo remove from hash.
148
149 //      citthread_mutex_unlock(&EventQueueMutex);
150 }
151
152 eReadState HandleInbound(AsyncIO *IO)
153 {
154         eReadState Finished = eBufferNotEmpty;
155                 
156         while ((Finished == eBufferNotEmpty) && (IO->NextState == eReadMessage)){
157                 if (IO->RecvBuf.nBlobBytesWanted != 0) { 
158                                 
159                 }
160                 else { /* Reading lines... */
161 //// lex line reply in callback, or do it ourselves. as nnn-blabla means continue reading in SMTP
162                         if (IO->LineReader)
163                                 Finished = IO->LineReader(IO);
164                         else 
165                                 Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf);
166                                 
167                         switch (Finished) {
168                         case eMustReadMore: /// read new from socket... 
169                                 return Finished;
170                                 break;
171                         case eBufferNotEmpty: /* shouldn't happen... */
172                         case eReadSuccess: /// done for now...
173                                 break;
174                         case eReadFail: /// WHUT?
175                                 ///todo: shut down! 
176                                 break;
177                         }
178                                         
179                 }
180                         
181                 if (Finished != eMustReadMore) {
182                         event_del(&IO->recv_event);
183                         IO->NextState = IO->ReadDone(IO->Data);
184                         Finished = StrBufCheckBuffer(&IO->RecvBuf);
185                 }
186         }
187
188
189         if ((IO->NextState == eSendReply) ||
190             (IO->NextState == eSendMore))
191         {
192                 IO->NextState = IO->SendDone(IO->Data);
193                 event_add(&IO->send_event, NULL);
194                         
195         }
196         else if ((IO->NextState == eTerminateConnection) ||
197                  (IO->NextState == eAbort) )
198                 ShutDownCLient(IO);
199         return Finished;
200 }
201
202
203 static void
204 IO_send_callback(int fd, short event, void *ctx)
205 {
206         int rc;
207         AsyncIO *IO = ctx;
208
209         (void)fd;
210         (void)event;
211         
212 ///    assert(fd == IO->sock);
213         
214         rc = StrBuf_write_one_chunk_callback(fd, event, &IO->SendBuf);
215
216         if (rc == 0)
217         {
218             event_del(&IO->send_event);
219             switch (IO->NextState) {
220             case eSendReply:
221                     break;
222             case eSendMore:
223                     IO->NextState = IO->SendDone(IO->Data);
224
225                     if ((IO->NextState == eTerminateConnection) ||
226                              (IO->NextState == eAbort) )
227                             ShutDownCLient(IO);
228                     else
229                             event_add(&IO->send_event, NULL);
230                     break;
231             case eReadMessage:
232                     if (StrBufCheckBuffer(&IO->RecvBuf) == eBufferNotEmpty) {
233                             HandleInbound(IO);
234                     }
235                     else {
236                             event_add(&IO->recv_event, NULL);
237                     }
238
239                     break;
240             case eAbort:
241                     break;
242             }
243         }
244         else if (rc > 0)
245                 return;
246 //      else 
247                 ///abort!
248 }
249
250
251 static void
252 IO_recv_callback(int fd, short event, void *ctx)
253 {
254         ssize_t nbytes;
255         AsyncIO *IO = ctx;
256
257 //    assert(fd == IO->sock);
258         
259 //    assert(fd == sb->fd);
260
261         nbytes = StrBuf_read_one_chunk_callback(fd, event, &IO->RecvBuf);
262         if (nbytes > 0) {
263                 HandleInbound(IO);
264         } else if (nbytes == 0) {
265                 ///  TODO: this is a timeout???  sock_buff_invoke_free(sb, 0);
266                 return;
267         } else if (nbytes == -1) {
268 /// TODO: FD is gone. kick it.        sock_buff_invoke_free(sb, errno);
269                 return;
270         }
271 }
272
273 void IOReadNextLine(AsyncIO *IO, int timeout)
274 {
275
276 }
277
278 void IOReadNextBLOB(AsyncIO *IO, int timeout, long size)
279 {
280 }
281
282 void InitEventIO(AsyncIO *IO, 
283                  void *pData, 
284                  IO_CallBack ReadDone, 
285                  IO_CallBack SendDone, 
286                  IO_CallBack Terminate, 
287                  IO_LineReaderCallback LineReader,
288                  int ReadFirst)
289 {
290         IO->Data = pData;
291         IO->SendDone = SendDone;
292         IO->ReadDone = ReadDone;
293         IO->Terminate = Terminate;
294         IO->LineReader = LineReader;
295
296         event_set(&IO->recv_event, 
297                   IO->sock, 
298                   EV_READ|EV_PERSIST,
299                   IO_recv_callback, 
300                   IO);
301
302         event_set(&IO->send_event, 
303                   IO->sock,
304                   EV_WRITE|EV_PERSIST,
305                   IO_send_callback, 
306                   IO);
307
308         if (ReadFirst) {
309                 IO->NextState = eReadMessage;
310                 event_add(&IO->recv_event, NULL);
311         }
312         else {
313                 IO->NextState = eSendReply;
314         }
315 }
316
317
318 #endif