Merge branch 'master' of git://git.exim.org/exim
[users/jgh/exim.git] / test / src / mtpscript.c
1 /* A little hacked up program that allows a script to play the part of a remote
2 SMTP/LMTP server on stdin/stdout for testing purposes. Hacked from the more
3 complicated version that does it over a socket. */
4
5
6 /* ANSI C standard includes */
7
8 #include <ctype.h>
9 #include <signal.h>
10 #include <stdarg.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16
17 /* Unix includes */
18
19 #include <errno.h>
20 #include <unistd.h>
21
22
23 static FILE *log;
24
25
26 /*************************************************
27 *            SIGALRM handler - crash out         *
28 *************************************************/
29
30 static void
31 sigalrm_handler(int sig)
32 {
33 sig = sig;    /* Keep picky compilers happy */
34 fprintf(log, "Server timed out\n");
35 exit(99);
36 }
37
38
39
40 /*************************************************
41 *                 Main Program                   *
42 *************************************************/
43
44 int main(int argc, char **argv)
45 {
46 char *logfile;
47 char *logmode = "w";
48 FILE *script;
49 unsigned char sbuffer[1024];
50 unsigned char ibuffer[1024];
51
52 if (argc < 3)
53   {
54   fprintf(stdout, "500 Script and log file required\n");
55   exit(1);
56   }
57
58 /* Get the script and log open */
59
60 script = fopen(argv[1], "r");
61 if (script == NULL)
62   {
63   fprintf(stdout, "500 Failed to open script %s: %s\r\n", argv[1],
64     strerror(errno));
65   exit(1);
66   }
67
68 logfile = argv[2];
69 if (logfile[0] == '+')
70   {
71   logfile++;
72   logmode = "a";
73   }
74
75 log = fopen(logfile, logmode);
76 if (log == NULL)
77   {
78   fprintf(stdout, "500 Failed to open log %s: %s\r\n", logfile,
79     strerror(errno));
80   exit(1);
81   }
82
83 /* SIGALRM handler crashes out */
84
85 signal(SIGALRM, sigalrm_handler);
86
87 /* Read the script, and do what it says. */
88
89 while (fgets(sbuffer, sizeof(sbuffer), script) != NULL)
90   {
91   int n = (int)strlen(sbuffer);
92   while (n > 0 && isspace(sbuffer[n-1])) n--;
93   sbuffer[n] = 0;
94
95   /* If the script line starts with a digit, it is a response line which
96   we are to send. */
97
98   if (isdigit(sbuffer[0]))
99     {
100     fprintf(log, "%s\n", sbuffer);
101     fflush(log);
102     fprintf(stdout, "%s\r\n", sbuffer);
103     fflush(stdout);
104     }
105
106   /* If the script line starts with "*sleep" we just sleep for a while
107   before continuing. Do not write this to the log, as it may not get
108   written at the right place in a log that's being shared. */
109
110   else if (strncmp(sbuffer, "*sleep ", 7) == 0)
111     {
112     sleep(atoi(sbuffer+7));
113     }
114
115   /* Otherwise the script line is the start of an input line we are expecting
116   from the client, or "*eof" indicating we expect the client to close the
117   connection. Read command line or data lines; the latter are indicated
118   by the expected line being just ".". */
119
120   else
121     {
122     int data = strcmp(sbuffer, ".") == 0;
123
124     fprintf(log, "%s\n", sbuffer);
125     fflush(log);
126
127     /* Loop for multiple data lines */
128
129     for (;;)
130       {
131       int n;
132       alarm(5);
133       if (fgets(ibuffer, sizeof(ibuffer), stdin) == NULL)
134         {
135         fprintf(log, "%sxpected EOF read from client\n",
136           (strncmp(sbuffer, "*eof", 4) == 0)? "E" : "Une");
137         goto END_OFF;
138         }
139       alarm(0);
140       n = (int)strlen(ibuffer);
141       while (n > 0 && isspace(ibuffer[n-1])) n--;
142       ibuffer[n] = 0;
143       fprintf(log, "<<< %s\n", ibuffer);
144       if (!data || strcmp(ibuffer, ".") == 0) break;
145       }
146
147     /* Check received what was expected */
148
149     if (strncmp(sbuffer, ibuffer, (int)strlen(sbuffer)) != 0)
150       {
151       fprintf(log, "Comparison failed - bailing out\n");
152       goto END_OFF;
153       }
154     }
155   }
156
157 /* This could appear in the wrong place in a shared log, so forgo it. */
158 /* fprintf(log, "End of script\n"); */
159
160 END_OFF:
161 fclose(script);
162 fclose(log);
163
164 exit(0);
165 }
166
167 /* End of mtpscript.c */