1 /* $Id: imap.c,v 1.13 2006/05/09 03:26:41 jared Exp $ */
2 #include "config.h"
3 
4 /* see RFC 2060 for protocol details
5  Excerpt included here:
6 
7 6.2.2.  LOGIN Command
8 
9    Arguments:  user name
10                password
11 
12    Responses:  no specific responses for this command
13 
14    Result:     OK - login completed, now in authenticated state
15                NO - login failure: user name or password rejected
16                BAD - command unknown or arguments invalid
17 
18       The LOGIN command identifies the client to the server and carries
19       the plaintext password authenticating this user.
20 
21    Example:    C: a001 LOGIN SMITH SESAME
22                S: a001 OK LOGIN completed
23 
24 6.1.3.  LOGOUT Command
25 
26    Arguments:  none
27 
28    Responses:  REQUIRED untagged response: BYE
29 
30    Result:     OK - logout completed
31                BAD - command unknown or arguments invalid
32 
33       The LOGOUT command informs the server that the client is done with
34       the connection.  The server MUST send a BYE untagged response
35       before the (tagged) OK response, and then close the network
36       connection.
37 
38    Example:    C: A023 LOGOUT
39                S: * BYE IMAP4rev1 Server logging out
40                S: A023 OK LOGOUT completed
41                (Server and client then close the connection)
42 
43  */
44 
45 struct imapdata {
46         time_t start; /* test start time */
47         time_t lastact; /* last activity */
48         int state;
49         };
50 
51 #define IMAP_CONNECT    1 /* doing a connect() */
52 #define IMAP_WAITBAN    2 /* Waiting for the banner */
53 #define IMAP_SENT_AUTH	3 /* sent our auth data */
54 #define IMAP_SENT_QUIT  4 /* sent logout */
55 #define IMAP_GOT_BYE    5 /* got a bye from the remote server */
56 
start_test_imap(struct monitorent * here,time_t now_t)57 void	start_test_imap(struct monitorent *here, time_t now_t)
58 {
59         struct imapdata *localstruct = NULL;
60         struct my_hostent *hp = NULL;
61         struct sockaddr_in name;
62         int serrno = -1, errcode = 0;
63 
64         /* Allocate our memory */
65         here->monitordata = MALLOC(sizeof(struct imapdata), "imap localstruct");
66 
67         localstruct = here->monitordata;
68 
69         localstruct->start = now_t;
70 
71         localstruct->lastact = localstruct->start;
72 
73         here->filedes = open_sock();
74 
75         if (here->filedes == -1)
76 	{
77 		here->retval = here->checkent->lastcheck;
78 		FREE(here->monitordata);
79 		here->monitordata = NULL;
80 		return;
81 	}
82 
83 
84         hp = my_gethostbyname(here->checkent->hostname, AF_INET);
85 
86 	if (hp == NULL)
87 	{
88 		here->retval = SYSM_NODNS;
89 		FREE(here->monitordata);
90 		here->monitordata = NULL;
91 		return;
92 	}
93 
94         /* zero out the space */
95         memset ( &name, 0, sizeof ( name ) );
96 
97         /* copy data */
98         memcpy((char*)&name.sin_addr, (char*)hp->my_h_addr_v4, hp->h_length_v4);
99 
100         /* set family type */
101         name.sin_family = AF_INET;
102 
103         /* set the port we're connecting to */
104         name.sin_port = htons(IMAP_PORTNUM);
105 
106         if (debug)
107 	{
108 		print_err(0, "start_test_imap() doing connect() to %s:%d\n",
109 			here->checkent->hostname, IMAP_PORTNUM);
110 	}
111 
112         errcode = connect(here->filedes, (struct sockaddr*)&name,
113                 sizeof(struct sockaddr_in));
114         serrno = errno;
115         if (debug)
116 	{
117                 perror("connect() in start_imap");
118 	}
119 
120         if ((errcode < 0) && (serrno != EINPROGRESS))
121         {
122                 close(here->filedes);
123 
124 		switch(serrno)
125 		{
126 			case ECONNREFUSED:
127 			case EINTR:
128 				here->retval = SYSM_CONNREF;
129 				break;
130 			case ENETUNREACH:
131 				here->retval = SYSM_NETUNRCH;
132 				break;
133 			case EHOSTDOWN:
134 			case EHOSTUNREACH:
135                         	here->retval = SYSM_HOSTDOWN;
136 				break;
137 			case ETIMEDOUT:
138                         	here->retval = SYSM_TIMEDOUT;
139 				break;
140                 }
141 
142                 /* Free memory we'd normally leak */
143                 FREE(localstruct);
144                 here->monitordata = NULL;
145 
146 		if (debug)
147 		{
148 			print_err(0, "imap.c: retval = %d\n", here->retval);
149 		}
150                 return;
151         }
152 
153         /* doing a connect() */
154         localstruct->state = IMAP_CONNECT;
155 
156         /* poll it again later */
157         return;
158 }
159 
service_test_imap(struct monitorent * here,time_t now_t)160 void	service_test_imap(struct monitorent *here, time_t now_t)
161 {
162         struct imapdata *localstruct = NULL;
163         char buffer[256], *retptr;
164         int isopenretval = -1;
165 
166         /* do some variable shufflign */
167         localstruct = here->monitordata;
168 
169 	if (localstruct == NULL)
170 	{
171 		print_err(1, "bug - localstruct == NULL in imap.c:service_test_imap\n");
172 		return;
173 	}
174 
175         if (debug)
176 	{
177                 print_err(0, "service_test_imap: state = %d\n", localstruct->state);
178 	}
179         /* do different things based on the state */
180         switch (localstruct->state)
181         {
182                 case IMAP_CONNECT:
183                 {
184                         isopenretval = is_open(here->filedes);
185                         if (debug)
186 			{
187 				print_err(0, "is_open is returning %d\n", isopenretval);
188 			}
189                         if ((isopenretval != -1) &&
190                                 (isopenretval != SYSM_INPROG))
191                         {
192                                 localstruct->lastact = now_t;
193                                 if (debug)
194 				{
195 					print_err(0, "is_open() in service_test_imap()\n");
196 				}
197                                 if (isopenretval != SYSM_OK)
198                                 {
199                                         here->retval = isopenretval;
200                                         close(here->filedes);
201                                         FREE(localstruct);
202                                         here->monitordata = NULL;
203                                         if (debug)
204 					{
205                                                 print_err(0, "ending service_test_imap() with retval = %s\n", errtostr(here->retval));
206 					}
207                                         return;
208                                 }
209                                 localstruct->state = IMAP_WAITBAN;
210                                 if (debug)
211 				{
212 					print_err(0, "connected() to the imap port of %s\n", here->checkent->hostname);
213 				}
214                         }
215                         break;
216                 }
217 
218                 case IMAP_WAITBAN:
219                 {
220                         if (data_waiting_read(here->filedes, 0))
221                         {
222                                 memset(buffer, 0, 256);
223                                 read(here->filedes, buffer, 254);
224                                 if (debug)
225 				{
226 					print_err(0, "imap.c:Got :%s:\n", buffer);
227 				}
228                                 if (strncmp(buffer, "* OK", 4) == 0)
229                                 {
230                                         /* prepare the buffer */
231                                         snprintf(buffer, 256, "A100 LOGIN %s %s",
232                                                 here->checkent->username,
233 						here->checkent->password);
234 
235                                         /* send the buffer out the socket */
236                                         sendline(here->filedes, buffer);
237                                         localstruct->state = IMAP_SENT_AUTH;
238                                 } else {
239                                         here->retval = SYSM_BAD_RESP;
240 				}
241                         }
242                         break;
243                 }
244 		case IMAP_SENT_AUTH:
245 		{
246                         if (data_waiting_read(here->filedes, 0))
247                         {
248                                 memset(buffer, 0, 256);
249                                 read(here->filedes, buffer, 254);
250                                 if (debug)
251 				{
252 					print_err(0, "imap.c:Got :%s:\n", buffer);
253 				}
254 				/* ditch informational msg(s) */
255 doover:				if (strncmp(buffer, "*", 1) == 0) {
256 				    if ((retptr = strchr(buffer, '\n')) != NULL) {
257 					strncpy(buffer, retptr + 1, 250);
258 					goto doover;
259 				    }
260 				}
261                                 if (strncmp(buffer, "A100 OK", 7) == 0)
262                                 {
263 					here->retval = SYSM_OK;
264 				} else if (strncmp(buffer, "A100 NO", 7) == 0)
265 				{
266 					here->retval = SYSM_BAD_AUTH;
267                                 } else {
268                                         here->retval = SYSM_BAD_RESP;
269                                 }
270 
271 				sendline(here->filedes, "A102 LOGOUT");
272 
273                                 /* send the buffer out the socket */
274                                 localstruct->state = IMAP_SENT_QUIT;
275                         }
276                         break;
277 		}
278 		case IMAP_SENT_QUIT:
279 		{
280                         if (data_waiting_read(here->filedes, 0))
281                         {
282                                 memset(buffer, 0, 256);
283                                 read(here->filedes, buffer, 254);
284                                 if (debug)
285 				{
286 					print_err(0, "imap.c:Got :%s:\n", buffer);
287 				}
288                                 if (strncmp(buffer, "A102 OK", 7) == 0)
289                                 {
290                                         here->retval = SYSM_OK;
291 					localstruct->state = IMAP_GOT_BYE;
292                                 } else {
293                                         here->retval = SYSM_BAD_RESP;
294                                 }
295                         }
296                         break;
297 		}
298 
299 
300 	} /* end of switch */
301         if (here->retval != -1)
302         {
303                 /* insert cleanup code here */
304                 close (here->filedes);
305                 FREE(localstruct);
306                 here->monitordata = NULL;
307         }
308         return;
309 
310 }
311 
stop_test_imap(struct monitorent * here)312 void    stop_test_imap(struct monitorent *here)
313 {
314         struct imapdata *localstruct = NULL;
315 
316         localstruct = here->monitordata;
317 	if (localstruct == NULL)
318 		return;
319 
320         close(here->filedes);
321         FREE(localstruct);
322         here->monitordata = NULL;
323         return;
324 
325 }
326 
327 
328