]> Pileus Git - ~andy/fetchmail/blob - imap.c
Major improvements in --check processing. New-message count is now visible.
[~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  "socket.h"
13 #include  "fetchmail.h"
14
15 static int count, seen, recent, unseen;
16
17 int imap_ok (socket, argbuf)
18 /* parse command response */
19 char *argbuf;
20 int socket;
21 {
22     int ok;
23     char buf [POPBUFSIZE+1];
24     char *bufp;
25     int n;
26
27     seen = 0;
28     do {
29         if (SockGets(socket, buf, sizeof(buf)) < 0)
30             return(PS_SOCKET);
31
32         if (outlevel == O_VERBOSE)
33             fprintf(stderr,"%s\n",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(socket, queryctl, buf)
75 /* apply for connection authorization */
76 int socket;
77 struct hostrec *queryctl;
78 char *buf;
79 {
80     /* try to get authorized */
81     return(gen_transact(socket,
82                   "LOGIN %s \"%s\"",
83                   queryctl->remotename, queryctl->password));
84 }
85
86 static imap_getrange(socket, queryctl, countp, newp)
87 /* get range of messages to be fetched */
88 int socket;
89 struct hostrec *queryctl;
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(socket,
97                   "SELECT %s",
98                   queryctl->mailbox[0] ? queryctl->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 imap_is_old(socket, queryctl, num)
115 int socket;
116 struct hostrec *queryctl;
117 int num;
118 {
119     char buf [POPBUFSIZE+1];
120     int ok;
121
122     if ((ok = gen_transact(socket, "FETCH %d FLAGS", num)) != 0)
123         exit(PS_ERROR);
124
125     return(seen);
126 }
127
128 static int imap_fetch(socket, number, lenp)
129 /* request nth message */
130 int socket;
131 int number;
132 int *lenp; 
133 {
134     char buf [POPBUFSIZE+1];
135     int num;
136
137     gen_send(socket, "FETCH %d RFC822", number);
138
139     /* looking for FETCH response */
140     do {
141         if (SockGets(socket, buf,sizeof(buf)) < 0)
142             return(PS_SOCKET);
143     } while
144             (sscanf(buf+2, "%d FETCH (RFC822 {%d}", &num, lenp) != 2);
145
146     if (num != number)
147         return(PS_ERROR);
148     else
149         return(0);
150 }
151
152 static imap_trail(socket, queryctl, number)
153 /* discard tail of FETCH response */
154 int socket;
155 struct hostrec *queryctl;
156 int number;
157 {
158     char buf [POPBUFSIZE+1];
159
160     if (SockGets(socket, buf,sizeof(buf)) < 0)
161         return(PS_SOCKET);
162     else
163         return(0);
164 }
165
166 static imap_delete(socket, queryctl, number)
167 /* set delete flag for given message */
168 int socket;
169 struct hostrec *queryctl;
170 int number;
171 {
172     /*
173      * I think the SILENT modifier here is the only thing keeping this code
174      * from being IMAP2 (RFC 1176-compliant), rather than IMAP2bis.  It's
175      * important for places where phone service is expensive to cut the
176      * IMAP protocol overhead as much as possible.
177      */
178     return(gen_transact(socket, "STORE %d +FLAGS.SILENT (\\Deleted)", number));
179 }
180
181 const static struct method imap =
182 {
183     "IMAP",             /* Internet Message Access Protocol */
184     143,                /* standard IMAP2bis/IMAP4 port */
185     1,                  /* this is a tagged protocol */
186     0,                  /* no message delimiter */
187     imap_ok,            /* parse command response */
188     imap_getauth,       /* get authorization */
189     imap_getrange,      /* query range of messages */
190     imap_is_old,        /* no UID check */
191     imap_fetch,         /* request given message */
192     imap_trail,         /* eat message trailer */
193     imap_delete,        /* set IMAP delete flag */
194     "EXPUNGE",          /* the IMAP expunge command */
195     "LOGOUT",           /* the IMAP exit command */
196 };
197
198 int doIMAP (queryctl)
199 /* retrieve messages using IMAP Version 2bis or Version 4 */
200 struct hostrec *queryctl;
201 {
202     return(do_protocol(queryctl, &imap));
203 }
204
205 /* imap.c ends here */