]>
diplodocus.org Git - nmh/blob - test/fakepop.c
1 /* fakepop - A fake POP server used by the nmh test suite
3 * This code is Copyright (c) 2012, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
13 #include <sys/types.h>
16 #define PIDFILE "/tmp/fakepop.pid"
20 #define CHECKUSER() if (!user) { \
21 putcrlf(s, "-ERR Aren't you forgetting " \
22 "something? Like the USER command?"); \
25 #define CHECKAUTH() if (!auth) { \
26 putcrlf(s, "-ERR Um, hello? Forget to " \
31 void putcrlf(int, char *);
32 int serve(const char *, const char *);
34 static void putpopbulk(int, char *);
35 static int getpop(int, char *, ssize_t
);
36 static char *readmessage(FILE *);
39 main(int argc
, char *argv
[])
43 int rc
, s
, user
= 0, auth
= 0, i
, j
;
49 fprintf(stderr
, "Usage: %s port username "
50 "password mail-file [mail-file ...]\n", argv
[0]);
54 if (strcmp(argv
[2], "XOAUTH") == 0) {
62 mfiles
= malloc(sizeof(FILE *) * numfiles
);
65 fprintf(stderr
, "Unable to allocate %d bytes for file "
66 "array\n", (int) (sizeof(FILE *) * numfiles
));
70 octets
= malloc(sizeof(*octets
) * numfiles
);
73 fprintf(stderr
, "Unable to allocate %d bytes for size "
74 "array\n", (int) (sizeof(FILE *) * numfiles
));
78 for (i
= 4, j
= 0; i
< argc
; i
++, j
++) {
79 if (!(mfiles
[j
] = fopen(argv
[i
], "r"))) {
80 fprintf(stderr
, "Unable to open message file \"%s\""
81 ": %s\n", argv
[i
], strerror(errno
));
86 * POP wants the size of the maildrop in bytes, but
87 * with \r\n line endings. Calculate that.
92 while (fgets(line
, sizeof(line
), mfiles
[j
])) {
93 octets
[j
] += strlen(line
);
94 if (strrchr(line
, '\n'))
101 s
= serve(PIDFILE
, argv
[1]);
104 * Pretend to be a POP server
107 putcrlf(s
, "+OK Not really a POP server, but we play one on TV");
110 char linebuf
[LINESIZE
];
112 rc
= getpop(s
, linebuf
, sizeof(linebuf
));
115 break; /* Error or EOF */
117 if (strcasecmp(linebuf
, "CAPA") == 0) {
118 putpopbulk(s
, "+OK We have no capabilities, really\r\n"
119 "FAKE-CAPABILITY\r\n");
120 if (xoauth
!= NULL
) {
121 putcrlf(s
, "SASL XOAUTH2");
124 } else if (strncasecmp(linebuf
, "USER ", 5) == 0) {
125 if (strcmp(linebuf
+ 5, argv
[2]) == 0) {
126 putcrlf(s
, "+OK Niiiice!");
129 putcrlf(s
, "-ERR Don't play me, bro!");
131 } else if (strncasecmp(linebuf
, "PASS ", 5) == 0) {
133 if (strcmp(linebuf
+ 5, argv
[3]) == 0) {
134 putcrlf(s
, "+OK Aren't you a sight "
138 putcrlf(s
, "-ERR C'mon!");
140 } else if (xoauth
!= NULL
141 && strncasecmp(linebuf
, "AUTH XOAUTH2", 12) == 0) {
142 if (strstr(linebuf
, xoauth
) == NULL
) {
143 putcrlf(s
, "+ base64-json-err");
144 rc
= getpop(s
, linebuf
, sizeof(linebuf
));
146 break; /* Error or EOF */
147 putcrlf(s
, "-ERR [AUTH] Invalid credentials.");
150 putcrlf(s
, "+OK Welcome.");
152 } else if (strcasecmp(linebuf
, "STAT") == 0) {
155 for (i
= 0, j
= 0; i
< numfiles
; i
++) {
161 snprintf(linebuf
, sizeof(linebuf
),
162 "+OK %d %d", i
, (int) total
);
164 } else if (strncasecmp(linebuf
, "RETR ", 5) == 0) {
166 rc
= sscanf(linebuf
+ 5, "%d", &i
);
168 putcrlf(s
, "-ERR Whaaaa...?");
171 if (i
< 1 || i
> numfiles
) {
172 putcrlf(s
, "-ERR That message number is "
173 "out of range, jerkface!");
176 if (mfiles
[i
- 1] == NULL
) {
177 putcrlf(s
, "-ERR Sorry, don't have it anymore");
179 char *buf
= readmessage(mfiles
[i
- 1]);
180 putcrlf(s
, "+OK Here you go ...");
184 } else if (strncasecmp(linebuf
, "DELE ", 5) == 0) {
186 rc
= sscanf(linebuf
+ 5, "%d", &i
);
188 putcrlf(s
, "-ERR Whaaaa...?");
191 if (i
< 1 || i
> numfiles
) {
192 putcrlf(s
, "-ERR That message number is "
193 "out of range, jerkface!");
196 if (mfiles
[i
- 1] == NULL
) {
197 putcrlf(s
, "-ERR Um, didn't you tell me "
198 "to delete it already?");
200 fclose(mfiles
[i
- 1]);
201 mfiles
[i
- 1] = NULL
;
202 putcrlf(s
, "+OK Alright man, I got rid of it");
204 } else if (strcasecmp(linebuf
, "QUIT") == 0) {
205 putcrlf(s
, "+OK See ya, wouldn't want to be ya!");
209 putcrlf(s
, "-ERR Um, what?");
217 * Put one big buffer to the POP server. Should have already had the line
218 * endings set up and dot-stuffed if necessary.
222 putpopbulk(int socket
, char *data
)
224 ssize_t datalen
= strlen(data
);
226 if (write(socket
, data
, datalen
) < 0) {
232 * Get one line from the POP server. We don't do any buffering here.
236 getpop(int socket
, char *data
, ssize_t len
)
242 cc
= read(socket
, data
+ offset
, len
- offset
);
245 fprintf(stderr
, "Read failed: %s\n", strerror(errno
));
256 fprintf(stderr
, "Input buffer overflow "
257 "(%d bytes)\n", (int) len
);
261 if (data
[offset
- 1] == '\n' && data
[offset
- 2] == '\r') {
262 data
[offset
- 2] = '\0';
268 #define HAVEROOM(buf, size, used, new) do { \
269 if (used + new > size - 1) { \
270 buf = realloc(buf, size += BUFALLOC); \
275 * Read a file and return it as one malloc()'d buffer. Convert \n to \r\n
276 * and dot-stuff if necessary.
280 readmessage(FILE *file
)
282 char *buffer
= malloc(BUFALLOC
);
283 ssize_t bufsize
= BUFALLOC
, used
= 0;
284 char linebuf
[LINESIZE
];
289 while (fgets(linebuf
, sizeof(linebuf
), file
)) {
290 if (strcmp(linebuf
, ".\n") == 0) {
291 HAVEROOM(buffer
, bufsize
, used
, 4);
292 strcat(buffer
, "..\r\n");
295 if (i
&& linebuf
[i
- 1] == '\n') {
296 HAVEROOM(buffer
, bufsize
, used
, i
+ 1);
297 linebuf
[i
- 1] = '\0';
298 strcat(buffer
, linebuf
);
299 strcat(buffer
, "\r\n");
301 HAVEROOM(buffer
, bufsize
, used
, i
);
302 strcat(buffer
, linebuf
);
308 * Put a terminating dot at the end
311 HAVEROOM(buffer
, bufsize
, used
, 3);
313 strcat(buffer
, ".\r\n");