summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/tests/smtpsend.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/tests/smtpsend.c') (more/less context) (ignore whitespace changes)
-rw-r--r--kmicromail/libetpan/tests/smtpsend.c278
1 files changed, 278 insertions, 0 deletions
diff --git a/kmicromail/libetpan/tests/smtpsend.c b/kmicromail/libetpan/tests/smtpsend.c
new file mode 100644
index 0000000..d5229d9
--- a/dev/null
+++ b/kmicromail/libetpan/tests/smtpsend.c
@@ -0,0 +1,278 @@
1/*
2 * Simple Mail Submission Agent using SMTP with libEtPan!
3 * TODO: Full sendmail like interface
4 */
5
6#include <libetpan/libetpan.h>
7#include <netdb.h>
8#include <netinet/in.h>
9#include <sys/socket.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/types.h>
13#include <sys/mman.h>
14#include <sys/stat.h>
15#include <unistd.h>
16#include <sys/ioctl.h>
17#include <fcntl.h>
18#include <pwd.h>
19
20#define _GNU_SOURCE
21#include <getopt.h>
22
23/* globals */
24char *smtp_server;
25uint smtp_port = 25;
26char *smtp_user;
27char *smtp_password;
28char *smtp_from;
29int smtp_tls = 0;
30int smtp_esmtp = 1;
31
32struct mem_message {
33 char *data;
34 size_t len;
35 MMAPString *mstring;
36};
37
38#define BLOCKSIZE 4096
39
40int collect(struct mem_message *message) {
41 struct stat sb;
42 int len;
43
44 memset(message, 0, sizeof(struct mem_message));
45
46 /* if stdin is a file whose size is known, try to mmap it */
47 if (!fstat(0, &sb) && S_ISREG(sb.st_mode) && sb.st_size >= 0) {
48 message->len = sb.st_size;
49 if ((message->data = mmap(NULL, message->len, PROT_READ, MAP_SHARED,
50 STDIN_FILENO, 0)) != MAP_FAILED)
51 return 0;
52 }
53
54 /* read the buffer from stdin by blocks, until EOF or error.
55 save the message in a mmap_string */
56 if ((message->mstring = mmap_string_sized_new(BLOCKSIZE)) == NULL) {
57 perror("mmap_string_new");
58 goto error;
59 }
60 message->len = 0;
61
62 while ((len = read(STDIN_FILENO,
63 message->mstring->str + message->len, BLOCKSIZE)) > 0) {
64 message->len += len;
65 /* reserve room for next block */
66 if ((mmap_string_set_size(message->mstring,
67 message->len + BLOCKSIZE)) == NULL) {
68 perror("mmap_string_set_size");
69 goto error;
70 }
71 }
72
73 if (len == 0) {
74 message->data = message->mstring->str;
75 return 0; /* OK */
76 }
77
78 perror("read");
79
80 error:
81 if (message->mstring != NULL)
82 mmap_string_free(message->mstring);
83 return -1;
84}
85
86char *guessfrom() {
87 uid_t uid;
88 struct passwd *pw;
89 char hostname[256];
90 int len;
91 char *gfrom;
92
93 if (gethostname(hostname, sizeof(hostname))) {
94 perror("gethostname");
95 return NULL;
96 }
97 hostname[sizeof(hostname) - 1] = '\0';
98
99 uid = getuid();
100 pw = getpwuid(uid);
101
102 len = ((pw != NULL) ? strlen(pw->pw_name) : 12)
103 + strlen(hostname) + 2;
104
105 if ((gfrom = malloc(len)) == NULL) {
106 perror("malloc");
107 return NULL;
108 }
109 if (pw != NULL && pw->pw_name != NULL)
110 snprintf(gfrom, len, "%s@%s", pw->pw_name, hostname);
111 else
112 snprintf(gfrom, len, "#%u@%s", uid, hostname);
113 return gfrom;
114}
115
116void release(struct mem_message *message) {
117 if (message->mstring != NULL)
118 mmap_string_free(message->mstring);
119 else if (message->data != NULL)
120 munmap(message->data, message->len);
121}
122
123int send_message(char *data, size_t len, char**rcpts) {
124 int s = -1;
125 int ret;
126 char **r;
127 int esmtp = 0;
128 mailsmtp *smtp = NULL;
129
130 if ((smtp = mailsmtp_new(0, NULL)) == NULL) {
131 perror("mailsmtp_new");
132 goto error;
133 }
134
135 /* first open the stream */
136 if ((ret = mailsmtp_socket_connect(smtp,
137 (smtp_server != NULL ? smtp_server : "localhost"),
138 smtp_port)) != MAILSMTP_NO_ERROR) {
139 fprintf(stderr, "mailsmtp_socket_connect: %s\n", mailsmtp_strerror(ret));
140 goto error;
141 }
142
143 /* then introduce ourselves */
144 if (smtp_esmtp && (ret = mailesmtp_ehlo(smtp)) == MAILSMTP_NO_ERROR)
145 esmtp = 1;
146 else if (!smtp_esmtp || ret == MAILSMTP_ERROR_NOT_IMPLEMENTED)
147 ret = mailsmtp_helo(smtp);
148 if (ret != MAILSMTP_NO_ERROR) {
149 fprintf(stderr, "mailsmtp_helo: %s\n", mailsmtp_strerror(ret));
150 goto error;
151 }
152
153 if (esmtp && smtp_tls &&
154 (ret = mailsmtp_socket_starttls(smtp)) != MAILSMTP_NO_ERROR) {
155 fprintf(stderr, "mailsmtp_starttls: %s\n", mailsmtp_strerror(ret));
156 goto error;
157 }
158
159 if (esmtp && smtp_user != NULL &&
160 (ret = mailsmtp_auth(smtp, smtp_user,
161 (smtp_password != NULL) ? smtp_password : ""))
162 != MAILSMTP_NO_ERROR) {
163 fprintf(stderr, "mailsmtp_auth: %s: %s\n", smtp_user, mailsmtp_strerror(ret));
164 goto error;
165 }
166
167 /* source */
168 if ((ret = (esmtp ?
169 mailesmtp_mail(smtp, smtp_from, 1, "etPanSMTPTest") :
170 mailsmtp_mail(smtp, smtp_from))) != MAILSMTP_NO_ERROR) {
171 fprintf(stderr, "mailsmtp_mail: %s, %s\n", smtp_from, mailsmtp_strerror(ret));
172 goto error;
173 }
174
175 /* recipients */
176 for (r = rcpts; *r != NULL; r++) {
177 if ((ret = (esmtp ?
178 mailesmtp_rcpt(smtp, *r,
179 MAILSMTP_DSN_NOTIFY_FAILURE|MAILSMTP_DSN_NOTIFY_DELAY,
180 NULL) :
181 mailsmtp_rcpt(smtp, *r))) != MAILSMTP_NO_ERROR) {
182 fprintf(stderr, "mailsmtp_rcpt: %s: %s\n", *r, mailsmtp_strerror(ret));
183 goto error;
184 }
185 }
186
187 /* message */
188 if ((ret = mailsmtp_data(smtp)) != MAILSMTP_NO_ERROR) {
189 fprintf(stderr, "mailsmtp_data: %s\n", mailsmtp_strerror(ret));
190 goto error;
191 }
192 if ((ret = mailsmtp_data_message(smtp, data, len)) != MAILSMTP_NO_ERROR) {
193 fprintf(stderr, "mailsmtp_data_message: %s\n", mailsmtp_strerror(ret));
194 goto error;
195 }
196 mailsmtp_free(smtp);
197 return 0;
198
199 error:
200 if (smtp != NULL)
201 mailsmtp_free(smtp);
202 if (s >= 0)
203 close(s);
204 return -1;
205}
206
207int main(int argc, char **argv) {
208 struct mem_message message;
209 int index, r;
210
211 static struct option long_options[] = {
212 {"server", 1, 0, 's'},
213 {"port", 1, 0, 'p'},
214 {"user", 1, 0, 'u'},
215 {"password", 1, 0, 'v'},
216 {"from", 1, 0, 'f'},
217 {"tls", 0, 0, 'S'},
218 {"no-esmtp", 0, 0, 'E'},
219 };
220
221 while(1) {
222 if ((r = getopt_long(argc, argv, "s:p:u:v:f:SE", long_options, &index)) < 0)
223 break;
224 switch (r) {
225 case 's':
226 if (smtp_server != NULL)
227 free(smtp_server);
228 smtp_server = strdup(optarg);
229 break;
230 case 'p':
231 smtp_port = strtoul(optarg, NULL, 10);
232 break;
233 case 'u':
234 if (smtp_user != NULL)
235 free(smtp_user);
236 smtp_user = strdup(optarg);
237 break;
238 case 'v':
239 if (smtp_password != NULL)
240 free(smtp_password);
241 smtp_password = strdup(optarg);
242 break;
243 case 'f':
244 if (smtp_from != NULL)
245 free(smtp_from);
246 smtp_from = strdup(optarg);
247 break;
248 case 'S':
249 smtp_tls = 1;
250 break;
251 case 'E':
252 smtp_esmtp = 0;
253 break;
254 }
255 }
256
257 argc -= optind;
258 argv += optind;
259
260 if (argc < 1) {
261 fprintf(stderr, "usage: smtpsend [-f from] [-u user] [-v password] [-s server] [-p port] [-S] <rcpts>...\n");
262 return EXIT_FAILURE;
263 }
264
265 if (smtp_from == NULL && (smtp_from = guessfrom()) == NULL) {
266 fprintf(stderr, "can't guess a valid from, please use -f option.\n");
267 return EXIT_FAILURE;
268 }
269
270 /* reads message from stdin */
271 if (collect(&message))
272 return EXIT_FAILURE;
273
274 send_message(message.data, message.len, argv);
275
276 release(&message);
277 return EXIT_SUCCESS;
278}