3 * Completely reworked version of "citmail"
4 * This program attempts to act like a local MDA if you're using sendmail or
5 * some other non-Citadel MTA. It basically just forwards the message to
6 * the Citadel SMTP listener on some non-standard port.
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
29 #include "citadel_decls.h"
36 #define INADDR_NONE 0xffffffff
42 void strip_trailing_nonprint(char *buf)
44 while ( (strlen(buf)>0) && (!isprint(buf[strlen(buf) - 1])) )
45 buf[strlen(buf) - 1] = 0;
53 void timeout(int signum)
59 int connectsock(char *host, char *service, char *protocol)
64 struct sockaddr_in sin;
66 struct sockaddr_un sun;
68 if ( (!strcmp(protocol, "unix")) || (atoi(service)<0) ) {
69 memset(&sun, 0, sizeof(sun));
70 sun.sun_family = AF_UNIX;
71 sprintf(sun.sun_path, USOCKPATH, 0-atoi(service) );
73 s = socket(AF_UNIX, SOCK_STREAM, 0);
75 fprintf(stderr, "Can't create socket: %s\n",
80 if (connect(s, (struct sockaddr *) &sun, sizeof(sun)) < 0) {
81 fprintf(stderr, "can't connect: %s\n",
90 /* otherwise it's a network connection */
92 memset(&sin, 0, sizeof(sin));
93 sin.sin_family = AF_INET;
95 pse = getservbyname(service, protocol);
97 sin.sin_port = pse->s_port;
98 } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
99 fprintf(stderr, "Can't get %s service entry: %s\n",
100 service, strerror(errno));
103 phe = gethostbyname(host);
105 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
106 } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
107 fprintf(stderr, "Can't get %s host entry: %s\n",
108 host, strerror(errno));
111 if ((ppe = getprotobyname(protocol)) == 0) {
112 fprintf(stderr, "Can't get %s protocol entry: %s\n",
113 protocol, strerror(errno));
116 if (!strcmp(protocol, "udp")) {
122 s = socket(PF_INET, type, ppe->p_proto);
124 fprintf(stderr, "Can't create socket: %s\n", strerror(errno));
127 signal(SIGALRM, timeout);
130 if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
131 fprintf(stderr, "can't connect to %s.%s: %s\n",
132 host, service, strerror(errno));
136 signal(SIGALRM, SIG_IGN);
142 * convert service and host entries into a six-byte numeric in the format
143 * expected by a SOCKS v4 server
145 void numericize(char *buf, char *host, char *service, char *protocol)
149 struct sockaddr_in sin;
151 memset(&sin, 0, sizeof(sin));
152 sin.sin_family = AF_INET;
154 pse = getservbyname(service, protocol);
156 sin.sin_port = pse->s_port;
157 } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
158 fprintf(stderr, "Can't get %s service entry: %s\n",
159 service, strerror(errno));
162 buf[1] = (((sin.sin_port) & 0xFF00) >> 8);
163 buf[0] = ((sin.sin_port) & 0x00FF);
165 phe = gethostbyname(host);
167 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
168 } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
169 fprintf(stderr, "Can't get %s host entry: %s\n",
170 host, strerror(errno));
173 buf[5] = ((sin.sin_addr.s_addr) & 0xFF000000) >> 24;
174 buf[4] = ((sin.sin_addr.s_addr) & 0x00FF0000) >> 16;
175 buf[3] = ((sin.sin_addr.s_addr) & 0x0000FF00) >> 8;
176 buf[2] = ((sin.sin_addr.s_addr) & 0x000000FF);
180 * input binary data from socket
182 void serv_read(char *buf, int bytes)
187 while (len < bytes) {
188 rlen = read(serv_sock, &buf[len], bytes - len);
198 * send binary to server
200 void serv_write(char *buf, int nbytes)
202 int bytes_written = 0;
204 while (bytes_written < nbytes) {
205 retval = write(serv_sock, &buf[bytes_written],
206 nbytes - bytes_written);
210 bytes_written = bytes_written + retval;
217 * input string from socket - implemented in terms of serv_read()
219 void serv_gets(char *buf)
223 /* Read one character at a time.
226 serv_read(&buf[i], 1);
227 if (buf[i] == '\n' || i == 255)
231 /* If we got a long line, discard characters until the newline.
234 while (buf[i] != '\n')
235 serv_read(&buf[i], 1);
237 /* Strip all trailing nonprintables (crlf)
240 strip_trailing_nonprint(buf);
245 * send line to server - implemented in terms of serv_write()
247 void serv_puts(char *buf)
249 /* printf("< %s\n", buf); */
250 serv_write(buf, strlen(buf));
258 void cleanup(int exitcode) {
263 fprintf(stderr, "%s\n", buf);
269 int main(int argc, char **argv) {
275 if (fp == NULL) return(errno);
276 sprintf(fromline, "From: someone@somewhere.org");
277 while (fgets(buf, 1024, stdin) != NULL) {
278 fprintf(fp, "%s", buf);
279 if (!strncasecmp(buf, "From:", 5)) strcpy(fromline, buf);
281 strip_trailing_nonprint(fromline);
283 sprintf(buf, "%d", SMTP_PORT);
284 serv_sock = connectsock("localhost", buf, "tcp");
286 fprintf(stderr, "%s\n", buf);
287 if (buf[0]!='2') cleanup(1);
289 serv_puts("HELO localhost");
291 fprintf(stderr, "%s\n", buf);
292 if (buf[0]!='2') cleanup(1);
294 sprintf(buf, "MAIL %s", fromline);
297 fprintf(stderr, "%s\n", buf);
298 if (buf[0]!='2') cleanup(1);
300 sprintf(buf, "RCPT To: %s", argv[1]);
303 fprintf(stderr, "%s\n", buf);
304 if (buf[0]!='2') cleanup(1);
308 fprintf(stderr, "%s\n", buf);
309 if (buf[0]!='3') cleanup(1);
312 while (fgets(buf, sizeof buf, fp) != NULL) {
313 strip_trailing_nonprint(buf);
318 fprintf(stderr, "%s\n", buf);
319 if (buf[0]!='2') cleanup(1);