libevent Migration
[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
81         QueueEventAddPtr = Ctx;
82         EventContextAttachPtr = CB;
83         QueueThisIO = IO;
84
85         write(event_add_pipe[1], "+_", 1);
86         citthread_mutex_unlock(&EventQueueMutex);
87         return 0;
88 }
89
90
91 int ShutDownEventQueue(void)
92 {
93         write(event_add_pipe[1], "x_", 1);
94         close(event_add_pipe[1]);
95         return 0;
96 }
97
98 void FreeAsyncIOContents(AsyncIO *IO)
99 {
100         FreeStrBuf(&IO->IOBuf);
101         FreeStrBuf(&IO->SendBuf.Buf);
102         FreeStrBuf(&IO->RecvBuf.Buf);
103
104 }
105
106 /*
107 static void
108 setup_signal_handlers(struct instance *instance)
109 {
110     signal(SIGPIPE, SIG_IGN);
111
112     event_set(&instance->sigterm_event, SIGTERM, EV_SIGNAL|EV_PERSIST,
113               exit_event_callback, instance);
114     event_add(&instance->sigterm_event, NULL);
115
116     event_set(&instance->sigint_event, SIGINT, EV_SIGNAL|EV_PERSIST,
117               exit_event_callback, instance);
118     event_add(&instance->sigint_event, NULL);
119
120     event_set(&instance->sigquit_event, SIGQUIT, EV_SIGNAL|EV_PERSIST,
121               exit_event_callback, instance);
122     event_add(&instance->sigquit_event, NULL);
123 }
124 */
125
126 void ShutDownCLient(AsyncIO *IO)
127 {
128         event_del(&IO->send_event);
129         event_del(&IO->recv_event);
130         IO->Terminate(IO->Data);
131
132 //      citthread_mutex_lock(&EventQueueMutex);
133
134 ///QueueEvents /// todo remove from hash.
135
136 //      citthread_mutex_unlock(&EventQueueMutex);
137 }
138
139 eReadState HandleInbound(AsyncIO *IO)
140 {
141         eReadState Finished = eBufferNotEmpty;
142                 
143         while ((Finished == eBufferNotEmpty) && (IO->NextState == eReadMessage)){
144                 if (IO->RecvBuf.nBlobBytesWanted != 0) { 
145                                 
146                 }
147                 else { /* Reading lines... */
148 //// lex line reply in callback, or do it ourselves. as nnn-blabla means continue reading in SMTP
149                         if (IO->LineReader)
150                                 Finished = IO->LineReader(IO);
151                         else 
152                                 Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf);
153                                 
154                         switch (Finished) {
155                         case eMustReadMore: /// read new from socket... 
156                                 return Finished;
157                                 break;
158                         case eBufferNotEmpty: /* shouldn't happen... */
159                         case eReadSuccess: /// done for now...
160                                 break;
161                         case eReadFail: /// WHUT?
162                                 ///todo: shut down! 
163                                 break;
164                         }
165                                         
166                 }
167                         
168                 if (Finished != eMustReadMore) {
169                         event_del(&IO->recv_event);
170                         IO->NextState = IO->ReadDone(IO->Data);
171                         Finished = StrBufCheckBuffer(&IO->RecvBuf);
172                 }
173         }
174
175
176         if ((IO->NextState == eSendReply) ||
177             (IO->NextState == eSendMore))
178         {
179                 IO->NextState = IO->SendDone(IO->Data);
180                 event_add(&IO->send_event, NULL);
181                         
182         }
183         else if ((IO->NextState == eTerminateConnection) ||
184                  (IO->NextState == eAbort) )
185                 ShutDownCLient(IO);
186         return Finished;
187 }
188
189
190 static void
191 IO_send_callback(int fd, short event, void *ctx)
192 {
193         int rc;
194         AsyncIO *IO = ctx;
195
196         (void)fd;
197         (void)event;
198         
199 ///    assert(fd == IO->sock);
200         
201         rc = StrBuf_write_one_chunk_callback(fd, event, &IO->SendBuf);
202
203         if (rc == 0)
204         {
205             event_del(&IO->send_event);
206             switch (IO->NextState) {
207             case eSendReply:
208                     break;
209             case eSendMore:
210                     IO->NextState = IO->SendDone(IO->Data);
211
212                     if ((IO->NextState == eTerminateConnection) ||
213                              (IO->NextState == eAbort) )
214                             ShutDownCLient(IO);
215                     else
216                             event_add(&IO->send_event, NULL);
217                     break;
218             case eReadMessage:
219                     if (StrBufCheckBuffer(&IO->RecvBuf) == eBufferNotEmpty) {
220                             HandleInbound(IO);
221                     }
222                     else {
223                             event_add(&IO->recv_event, NULL);
224                     }
225
226                     break;
227             case eAbort:
228                     break;
229             }
230         }
231         else if (rc > 0)
232                 return;
233 //      else 
234                 ///abort!
235 }
236
237
238 static void
239 IO_recv_callback(int fd, short event, void *ctx)
240 {
241         ssize_t nbytes;
242         AsyncIO *IO = ctx;
243
244 //    assert(fd == IO->sock);
245         
246 //    assert(fd == sb->fd);
247
248         nbytes = StrBuf_read_one_chunk_callback(fd, event, &IO->RecvBuf);
249         if (nbytes > 0) {
250                 HandleInbound(IO);
251         } else if (nbytes == 0) {
252                 ///  TODO: this is a timeout???  sock_buff_invoke_free(sb, 0);
253                 return;
254         } else if (nbytes == -1) {
255 /// TODO: FD is gone. kick it.        sock_buff_invoke_free(sb, errno);
256                 return;
257         }
258 }
259
260 void IOReadNextLine(AsyncIO *IO, int timeout)
261 {
262
263 }
264
265 void IOReadNextBLOB(AsyncIO *IO, int timeout, long size)
266 {
267 }
268
269 void InitEventIO(AsyncIO *IO, 
270                  void *pData, 
271                  IO_CallBack ReadDone, 
272                  IO_CallBack SendDone, 
273                  IO_CallBack Terminate, 
274                  IO_LineReaderCallback LineReader,
275                  int ReadFirst)
276 {
277         IO->Data = pData;
278         IO->SendDone = SendDone;
279         IO->ReadDone = ReadDone;
280         IO->Terminate = Terminate;
281         IO->LineReader = LineReader;
282
283         event_set(&IO->recv_event, 
284                   IO->sock, 
285                   EV_READ|EV_PERSIST,
286                   IO_recv_callback, 
287                   IO);
288
289         event_set(&IO->send_event, 
290                   IO->sock,
291                   EV_WRITE|EV_PERSIST,
292                   IO_send_callback, 
293                   IO);
294
295         if (ReadFirst) {
296                 IO->NextState = eReadMessage;
297                 event_add(&IO->recv_event, NULL);
298         }
299         else {
300                 IO->NextState = eSendReply;
301         }
302 }
303
304
305 #endif