Diffstat (limited to 'kmicromail/libetpan/tests/smtpsend.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | kmicromail/libetpan/tests/smtpsend.c | 278 |
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 */ | ||
24 | char *smtp_server; | ||
25 | uint smtp_port = 25; | ||
26 | char *smtp_user; | ||
27 | char *smtp_password; | ||
28 | char *smtp_from; | ||
29 | int smtp_tls = 0; | ||
30 | int smtp_esmtp = 1; | ||
31 | |||
32 | struct mem_message { | ||
33 | char *data; | ||
34 | size_t len; | ||
35 | MMAPString *mstring; | ||
36 | }; | ||
37 | |||
38 | #define BLOCKSIZE 4096 | ||
39 | |||
40 | int 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 | |||
86 | char *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 | |||
116 | void 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 | |||
123 | int 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 | |||
207 | int 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 | } | ||