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