]> Pileus Git - ~andy/fetchmail/blob - imap.c
944c246bc846806f6e8fb5e970884094447b5457
[~andy/fetchmail] / imap.c
1 /*
2  * imap.c -- IMAP2bis/IMAP4 protocol methods
3  *
4  * Copyright 1996 by Eric S. Raymond
5  * All rights reserved.
6  * For license terms, see the file COPYING in this directory.
7  */
8
9 #include  <config.h>
10 #include  <stdio.h>
11 #include  <string.h>
12 #include  <ctype.h>
13 #if defined(STDC_HEADERS)
14 #include  <stdlib.h>
15 #endif
16 #include  "fetchmail.h"
17
18 static int count, seen, recent, unseen, imap4;
19
20 int imap_ok (FILE *sockfp,  char *argbuf)
21 /* parse command response */
22 {
23     char buf [POPBUFSIZE+1];
24
25     seen = 0;
26     do {
27         if (!fgets(buf, sizeof(buf), sockfp))
28             return(PS_SOCKET);
29         if (buf[strlen(buf)-1] == '\n')
30             buf[strlen(buf)-1] = '\0';
31         if (buf[strlen(buf)-1] == '\r')
32             buf[strlen(buf)-1] = '\r';
33
34         if (outlevel == O_VERBOSE)
35             error(0, 0, "IMAP< %s", buf);
36
37         /* interpret untagged status responses */
38         if (strstr(buf, "EXISTS"))
39             count = atoi(buf+2);
40         if (strstr(buf, "RECENT"))
41             recent = atoi(buf+2);
42         if (strstr(buf, "UNSEEN"))
43             unseen = atoi(buf+2);
44         if (strstr(buf, "FLAGS"))
45             seen = (strstr(buf, "Seen") != (char *)NULL);
46     } while
47         (tag[0] != '\0' && strncmp(buf, tag, strlen(tag)));
48
49     if (tag[0] == '\0')
50     {
51         strcpy(argbuf, buf);
52         return(0); 
53     }
54     else
55     {
56         char    *cp;
57
58         /* skip the tag */
59         for (cp = buf; !isspace(*cp); cp++)
60             continue;
61         while (isspace(*cp))
62             cp++;
63
64         if (strncmp(cp, "OK", 2) == 0)
65         {
66             strcpy(argbuf, cp);
67             return(0);
68         }
69         else if (strncmp(cp, "BAD", 2) == 0)
70             return(PS_ERROR);
71         else
72             return(PS_PROTOCOL);
73     }
74 }
75
76 int imap_getauth(FILE *sockfp, struct query *ctl, char *buf)
77 /* apply for connection authorization */
78 {
79     /* try to get authorized */
80     int ok = gen_transact(sockfp,
81                   "LOGIN %s \"%s\"",
82                   ctl->remotename, ctl->password);
83
84     if (ok)
85         return(ok);
86
87     /* probe to see if we're running IMAP4 and can use RFC822.PEEK */
88     imap4 = ((gen_transact(sockfp, "CAPABILITY")) == 0);
89
90     return(0);
91 }
92
93 static int imap_getrange(FILE *sockfp, struct query *ctl, int*countp, int*newp)
94 /* get range of messages to be fetched */
95 {
96     int ok;
97
98     /* find out how many messages are waiting */
99     recent = unseen = 0;
100     ok = gen_transact(sockfp,
101                   "SELECT %s",
102                   ctl->mailbox[0] ? ctl->mailbox : "INBOX");
103     if (ok != 0)
104         return(ok);
105
106     *countp = count;
107
108     if (unseen)         /* optional response, but better if we see it */
109         *newp = unseen;
110     else if (recent)    /* mandatory */
111         *newp = recent;
112     else
113         *newp = -1;     /* should never happen, RECENT is mandatory */ 
114
115     return(0);
116 }
117
118 static int imap_getsizes(FILE *sockfp, int count, int *sizes)
119 /* capture the sizes of all messages */
120 {
121     char buf [POPBUFSIZE+1];
122
123     gen_send(sockfp, "FETCH 1:%d RFC822.SIZE", count);
124     while (fgets(buf, sizeof(buf), sockfp))
125     {
126         int num, size;
127
128         if (buf[strlen(buf)-1] == '\n')
129             buf[strlen(buf)-1] = '\0';
130         if (buf[strlen(buf)-1] == '\r')
131             buf[strlen(buf)-1] = '\r';
132         if (outlevel == O_VERBOSE)
133             error(0, 0, "IMAP< %s", buf);
134         if (strstr(buf, "OK"))
135             break;
136         else if (sscanf(buf, "* %d FETCH (RFC822.SIZE %d)", &num, &size) == 2)
137             sizes[num - 1] = size;
138         else
139             sizes[num - 1] = -1;
140     }
141
142     return(0);
143 }
144
145 static int imap_is_old(FILE *sockfp, struct query *ctl, int num)
146 /* is the given message old? */
147 {
148     int ok;
149
150     if ((ok = gen_transact(sockfp, "FETCH %d FLAGS", num)) != 0)
151         return(PS_ERROR);
152
153     return(seen);
154 }
155
156 static int imap_fetch(FILE *sockfp, int number, int *lenp)
157 /* request nth message */
158 {
159     char buf [POPBUFSIZE+1];
160     int num;
161
162     /*
163      * If we're using IMAP4, we can fetch the message without setting its
164      * seen flag.  This is good!  It means that if the protocol exchange
165      * craps out during the message, it will still be marked `unseen' on
166      * the server.
167      */
168     if (imap4)
169         gen_send(sockfp, "FETCH %d RFC822.PEEK", number);
170     else
171         gen_send(sockfp, "FETCH %d RFC822", number);
172
173     /* looking for FETCH response */
174     do {
175         if (!fgets(buf, sizeof(buf), sockfp))
176             return(PS_SOCKET);
177     } while
178             (sscanf(buf+2, "%d FETCH (RFC822 {%d}", &num, lenp) != 2);
179
180     if (num != number)
181         return(PS_ERROR);
182     else
183         return(0);
184 }
185
186 static int imap_trail(FILE *sockfp, struct query *ctl, int number)
187 /* discard tail of FETCH response after reading message text */
188 {
189     char buf [POPBUFSIZE+1];
190
191     if (!fgets(buf, sizeof(buf), sockfp))
192         return(PS_SOCKET);
193     else
194         return(0);
195 }
196
197 static int imap_delete(FILE *sockfp, struct query *ctl, int number)
198 /* set delete flag for given message */
199 {
200     /* use SILENT if possible as a minor throughput optimization */
201     return(gen_transact(sockfp,
202                         imap4 
203                                 ? "STORE %d +FLAGS.SILENT (\\Deleted)"
204                                 : "STORE %d +FLAGS (\\Deleted)", 
205                         number));
206 }
207
208 const static struct method imap =
209 {
210     "IMAP",             /* Internet Message Access Protocol */
211     143,                /* standard IMAP2bis/IMAP4 port */
212     1,                  /* this is a tagged protocol */
213     0,                  /* no message delimiter */
214     imap_ok,            /* parse command response */
215     imap_getauth,       /* get authorization */
216     imap_getrange,      /* query range of messages */
217     imap_getsizes,      /* grab message sizes */
218     imap_is_old,        /* no UID check */
219     imap_fetch,         /* request given message */
220     imap_trail,         /* eat message trailer */
221     imap_delete,        /* set IMAP delete flag */
222     "EXPUNGE",          /* the IMAP expunge command */
223     "LOGOUT",           /* the IMAP exit command */
224 };
225
226 int doIMAP(struct query *ctl)
227 /* retrieve messages using IMAP Version 2bis or Version 4 */
228 {
229     return(do_protocol(ctl, &imap));
230 }
231
232 /* imap.c ends here */