3 * Copyright (c) 1998-2009 by the citadel.org team
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.
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.
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
29 #include <sys/types.h>
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
37 # include <sys/time.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <libcitadel.h>
52 #include "citserver.h"
59 #include "internet_addressing.h"
62 #include "clientsocket.h"
63 #include "locate_host.h"
64 #include "citadel_dirs.h"
66 #ifdef EXPERIMENTAL_SMTP_EVENT_CLIENT
69 #include "event_client.h"
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;
77 int QueueEventContext(void *Ctx, AsyncIO *IO, EventContextAttach CB)
79 citthread_mutex_lock(&EventQueueMutex);
80 if (event_add_pipe[1] == -1) {
81 citthread_mutex_unlock(&EventQueueMutex);
86 QueueEventAddPtr = Ctx;
87 EventContextAttachPtr = CB;
90 write(event_add_pipe[1], "+_", 1);
91 citthread_mutex_unlock(&EventQueueMutex);
96 int ShutDownEventQueue(void)
98 citthread_mutex_lock(&EventQueueMutex);
99 if (event_add_pipe[1] == -1) {
100 citthread_mutex_unlock(&EventQueueMutex);
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);
111 void FreeAsyncIOContents(AsyncIO *IO)
113 FreeStrBuf(&IO->IOBuf);
114 FreeStrBuf(&IO->SendBuf.Buf);
115 FreeStrBuf(&IO->RecvBuf.Buf);
121 setup_signal_handlers(struct instance *instance)
123 signal(SIGPIPE, SIG_IGN);
125 event_set(&instance->sigterm_event, SIGTERM, EV_SIGNAL|EV_PERSIST,
126 exit_event_callback, instance);
127 event_add(&instance->sigterm_event, NULL);
129 event_set(&instance->sigint_event, SIGINT, EV_SIGNAL|EV_PERSIST,
130 exit_event_callback, instance);
131 event_add(&instance->sigint_event, NULL);
133 event_set(&instance->sigquit_event, SIGQUIT, EV_SIGNAL|EV_PERSIST,
134 exit_event_callback, instance);
135 event_add(&instance->sigquit_event, NULL);
139 void ShutDownCLient(AsyncIO *IO)
141 event_del(&IO->send_event);
142 event_del(&IO->recv_event);
143 IO->Terminate(IO->Data);
145 // citthread_mutex_lock(&EventQueueMutex);
147 ///QueueEvents /// todo remove from hash.
149 // citthread_mutex_unlock(&EventQueueMutex);
152 eReadState HandleInbound(AsyncIO *IO)
154 eReadState Finished = eBufferNotEmpty;
156 while ((Finished == eBufferNotEmpty) && (IO->NextState == eReadMessage)){
157 if (IO->RecvBuf.nBlobBytesWanted != 0) {
160 else { /* Reading lines... */
161 //// lex line reply in callback, or do it ourselves. as nnn-blabla means continue reading in SMTP
163 Finished = IO->LineReader(IO);
165 Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf);
168 case eMustReadMore: /// read new from socket...
171 case eBufferNotEmpty: /* shouldn't happen... */
172 case eReadSuccess: /// done for now...
174 case eReadFail: /// WHUT?
181 if (Finished != eMustReadMore) {
182 event_del(&IO->recv_event);
183 IO->NextState = IO->ReadDone(IO->Data);
184 Finished = StrBufCheckBuffer(&IO->RecvBuf);
189 if ((IO->NextState == eSendReply) ||
190 (IO->NextState == eSendMore))
192 IO->NextState = IO->SendDone(IO->Data);
193 event_add(&IO->send_event, NULL);
196 else if ((IO->NextState == eTerminateConnection) ||
197 (IO->NextState == eAbort) )
204 IO_send_callback(int fd, short event, void *ctx)
212 /// assert(fd == IO->sock);
214 rc = StrBuf_write_one_chunk_callback(fd, event, &IO->SendBuf);
218 event_del(&IO->send_event);
219 switch (IO->NextState) {
223 IO->NextState = IO->SendDone(IO->Data);
225 if ((IO->NextState == eTerminateConnection) ||
226 (IO->NextState == eAbort) )
229 event_add(&IO->send_event, NULL);
232 if (StrBufCheckBuffer(&IO->RecvBuf) == eBufferNotEmpty) {
236 event_add(&IO->recv_event, NULL);
252 IO_recv_callback(int fd, short event, void *ctx)
257 // assert(fd == IO->sock);
259 // assert(fd == sb->fd);
261 nbytes = StrBuf_read_one_chunk_callback(fd, event, &IO->RecvBuf);
264 } else if (nbytes == 0) {
265 /// TODO: this is a timeout??? sock_buff_invoke_free(sb, 0);
267 } else if (nbytes == -1) {
268 /// TODO: FD is gone. kick it. sock_buff_invoke_free(sb, errno);
273 void IOReadNextLine(AsyncIO *IO, int timeout)
278 void IOReadNextBLOB(AsyncIO *IO, int timeout, long size)
282 void InitEventIO(AsyncIO *IO,
284 IO_CallBack ReadDone,
285 IO_CallBack SendDone,
286 IO_CallBack Terminate,
287 IO_LineReaderCallback LineReader,
291 IO->SendDone = SendDone;
292 IO->ReadDone = ReadDone;
293 IO->Terminate = Terminate;
294 IO->LineReader = LineReader;
296 event_set(&IO->recv_event,
302 event_set(&IO->send_event,
309 IO->NextState = eReadMessage;
310 event_add(&IO->recv_event, NULL);
313 IO->NextState = eSendReply;