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