smtp-client
SMTP Client C Library
mailx.c
Go to the documentation of this file.
1 
17 #define _POSIX_C_SOURCE 200809L
18 
19 #include <err.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include "smtp.h"
26 
35 
39  char email[1000];
40 };
41 
50  char name[1000];
51 
55  char path[1000];
56 };
57 
62 struct mailx{
66  struct smtp *smtp;
67 
71  const char *subject;
72 
76  char *body;
77 
81  char *server;
82 
86  char *port;
87 
91  char *user;
92 
96  char *pass;
97 
101  char *from;
102 
106  enum smtp_connection_security connection_security;
107 
111  enum smtp_authentication_method auth_method;
112 
118  enum smtp_flag smtp_flags;
119 
124 
128  size_t num_address;
129 
134 
139 };
140 
152 static char *
154  size_t *bytes_read){
155  char *read_buf;
156  size_t bufsz;
157  char *new_buf;
158  const size_t BUFSZ_INCREMENT = 512;
159 
160  read_buf = NULL;
161  bufsz = 0;
162 
163  if(bytes_read){
164  *bytes_read = 0;
165  }
166 
167  do{
168  size_t bytes_read_loop;
169  if((new_buf = realloc(read_buf, bufsz + BUFSZ_INCREMENT)) == NULL){
170  free(read_buf);
171  return NULL;
172  }
173  read_buf = new_buf;
174  bufsz += BUFSZ_INCREMENT;
175 
176  bytes_read_loop = fread(&read_buf[bufsz - BUFSZ_INCREMENT],
177  sizeof(char),
178  BUFSZ_INCREMENT,
179  stream);
180  if(bytes_read){
181  *bytes_read += bytes_read_loop;
182  }
183  if(ferror(stream)){
184  free(read_buf);
185  return NULL;
186  }
187  } while(!feof(stream));
188 
189  return read_buf;
190 }
191 
199 static void
202  const char *const email){
203  struct mailx_address *new_address;
204  size_t new_address_list_sz;
205 
206  mailx->num_address += 1;
207  new_address_list_sz = mailx->num_address * sizeof(*mailx->address_list);
208  if((mailx->address_list = realloc(mailx->address_list,
209  new_address_list_sz)) == NULL){
210  err(1, "realloc");
211  }
212 
213  new_address = &mailx->address_list[mailx->num_address - 1];
214  new_address->address_type = address_type;
215  strncpy(new_address->email, email, sizeof(new_address->email));
216  new_address->email[sizeof(new_address->email) - 1] = '\0';
217 }
218 
224 static void
225 mailx_send(struct mailx *const mailx){
226  int rc;
227  size_t i;
228  const struct mailx_address *address;
229  const struct mailx_attachment *attachment;
230 
231  smtp_open(mailx->server,
232  mailx->port,
233  mailx->connection_security,
234  mailx->smtp_flags,
235  NULL,
236  &mailx->smtp);
237 
238  smtp_auth(mailx->smtp,
239  mailx->auth_method,
240  mailx->user,
241  mailx->pass);
242 
243  for(i = 0; i < mailx->num_address; i++){
244  address = &mailx->address_list[i];
245  smtp_address_add(mailx->smtp, address->address_type, address->email, NULL);
246  }
247 
248  for(i = 0; i < mailx->num_attachment; i++){
249  attachment = &mailx->attachment_list[i];
250  smtp_attachment_add_path(mailx->smtp, attachment->name, attachment->path);
251  }
252  smtp_header_add(mailx->smtp, "Subject", mailx->subject);
253  smtp_mail(mailx->smtp, mailx->body);
254 
255  rc = smtp_close(mailx->smtp);
256 
257  if(rc != SMTP_STATUS_OK){
258  errx(1, "%s", smtp_status_code_errstr(rc));
259  }
260 }
261 
269 static void
271  const char *const filename,
272  const char *const path){
273  struct mailx_attachment *new_attachment;
274  size_t new_attachment_list_sz;
275 
276  if(filename == NULL || path == NULL){
277  errx(1, "must provide attachment with valid name:path");
278  }
279 
280  new_attachment_list_sz = (mailx->num_attachment + 1) *
281  sizeof(*mailx->attachment_list);
282  if((mailx->attachment_list = realloc(mailx->attachment_list,
283  new_attachment_list_sz)) == NULL){
284  err(1, "realloc: attachment list");
285  }
286  new_attachment = &mailx->attachment_list[mailx->num_attachment];
287  mailx->num_attachment += 1;
288 
289  strncpy(new_attachment->name, filename, sizeof(new_attachment->name));
290  new_attachment->name[sizeof(new_attachment->name) - 1] = '\0';
291 
292  strncpy(new_attachment->path, path, sizeof(new_attachment->path));
293  new_attachment->path[sizeof(new_attachment->path) - 1] = '\0';
294 }
295 
302 static void
304  const char *const attach_arg){
305  char *attach_arg_dup;
306  char *filename;
307  char *filepath;
308 
309  if((attach_arg_dup = strdup(attach_arg)) == NULL){
310  err(1, "strdup: %s", attach_arg);
311  }
312 
313  filename = strtok(attach_arg_dup, ":");
314  filepath = strtok(NULL, ":");
315 
316  mailx_append_attachment(mailx, filename, filepath);
317 
318  free(attach_arg_dup);
319 }
320 
329 static void
331  const char *const option){
332  char *optdup;
333  char *opt_key;
334  char *opt_value;
335  int rc;
336 
337  rc = 0;
338 
339  if((optdup = strdup(option)) == NULL){
340  err(1, "strdup: option: %s", option);
341  }
342 
343  if((opt_key = strtok(optdup, "=")) == NULL){
344  errx(1, "strtok: %s", optdup);
345  }
346 
347  opt_value = strtok(NULL, "=");
348 
349  if(strcmp(opt_key, "smtp-security") == 0){
350  if(strcmp(opt_value, "none") == 0){
352  }
353 #ifdef SMTP_OPENSSL
354  else if(strcmp(opt_value, "tls") == 0){
356  }
357  else if(strcmp(opt_value, "starttls") == 0){
359  }
360 #endif /* SMTP_OPENSSL */
361  else{
362  rc = -1;
363  }
364  }
365  else if(strcmp(opt_key, "smtp-auth") == 0){
366  if(strcmp(opt_value, "none") == 0){
367  mailx->auth_method = SMTP_AUTH_NONE;
368  }
369  else if(strcmp(opt_value, "plain") == 0){
370  mailx->auth_method = SMTP_AUTH_PLAIN;
371  }
372  else if(strcmp(opt_value, "login") == 0){
373  mailx->auth_method = SMTP_AUTH_LOGIN;
374  }
375 #ifdef SMTP_OPENSSL
376  else if(strcmp(opt_value, "cram-md5") == 0){
378  }
379 #endif /* SMTP_OPENSSL */
380  else{
381  rc = -1;
382  }
383  }
384  else if(strcmp(opt_key, "smtp-flag") == 0){
385  if(strcmp(opt_value, "debug") == 0){
386  mailx->smtp_flags |= SMTP_DEBUG;
387  }
388  else if(strcmp(opt_value, "no-cert-verify") == 0){
390  }
391  else{
392  rc = -1;
393  }
394  }
395  else if(strcmp(opt_key, "smtp-server") == 0){
396  if((mailx->server = strdup(opt_value)) == NULL){
397  err(1, "strdup");
398  }
399  }
400  else if(strcmp(opt_key, "smtp-port") == 0){
401  if((mailx->port = strdup(opt_value)) == NULL){
402  err(1, "strdup");
403  }
404  }
405  else if(strcmp(opt_key, "smtp-user") == 0){
406  if((mailx->user = strdup(opt_value)) == NULL){
407  err(1, "strdup");
408  }
409  }
410  else if(strcmp(opt_key, "smtp-pass") == 0){
411  if((mailx->pass = strdup(opt_value)) == NULL){
412  err(1, "strdup");
413  }
414  }
415  else if(strcmp(opt_key, "smtp-from") == 0){
416  if((mailx->from = strdup(opt_value)) == NULL){
417  err(1, "strdup");
418  }
419  }
420  else{
421  rc = -1;
422  }
423 
424  free(optdup);
425 
426  if(rc < 0){
427  errx(1, "invalid argument: %s", option);
428  }
429 }
430 
438 static void
440  memset(mailx, 0, sizeof(*mailx));
441  mailx->subject = "";
443  mailx->auth_method = SMTP_AUTH_NONE;
444 }
445 
451 static void
452 mailx_free(const struct mailx *const mailx){
453  free(mailx->body);
454  free(mailx->server);
455  free(mailx->port);
456  free(mailx->user);
457  free(mailx->pass);
458  free(mailx->from);
459 }
460 
498 int main(int argc, char *argv[]){
499  int rc;
500  int i;
501  struct mailx mailx;
502 
504 
505  while((rc = getopt(argc, argv, "a:s:S:")) != -1){
506  switch(rc){
507  case 'a':
508  mailx_append_attachment_arg(&mailx, optarg);
509  break;
510  case 's':
511  mailx.subject = optarg;
512  break;
513  case 'S':
514  mailx_parse_smtp_option(&mailx, optarg);
515  break;
516  default:
517  return 1;
518  }
519  }
520  argc -= optind;
521  argv += optind;
522 
523  if(argc < 1){
524  errx(1, "must provide at least one email destination address");
525  }
526 
527  if(mailx.from == NULL){
528  errx(1, "must provide a FROM address");
529  }
530 
531  if(mailx.server == NULL){
532  if((mailx.server = strdup("localhost")) == NULL){
533  err(1, "strdup");
534  }
535  }
536 
537  if(mailx.port == NULL){
538  if((mailx.port = strdup("25")) == NULL){
539  err(1, "strdup");
540  }
541  }
542 
543  puts("Reading email body from stdin");
544  if((mailx.body = smtp_ffile_get_contents(stdin, NULL)) == NULL){
545  err(1, "failed to read email body from stdin");
546  }
547 
549 
550  for(i = 0; i < argc; i++){
551  mailx_address_append(&mailx, SMTP_ADDRESS_TO, argv[i]);
552  }
553 
554  mailx_send(&mailx);
555  mailx_free(&mailx);
556  return 0;
557 }
558 
enum smtp_status_code smtp_close(struct smtp *smtp)
Definition: smtp.c:3168
const char * smtp_status_code_errstr(enum smtp_status_code status_code)
Definition: smtp.c:3241
const char * subject
Definition: mailx.c:71
char * user
Definition: mailx.c:91
enum smtp_connection_security connection_security
Definition: mailx.c:106
char path[1000]
Definition: mailx.c:55
enum smtp_status_code smtp_header_add(struct smtp *const smtp, const char *const key, const char *const value)
Definition: smtp.c:3278
#define ferror
Definition: seams.h:113
enum smtp_authentication_method auth_method
Definition: mailx.c:111
char * from
Definition: mailx.c:101
static void mailx_parse_smtp_option(struct mailx *const mailx, const char *const option)
Definition: mailx.c:330
enum smtp_status_code smtp_mail(struct smtp *const smtp, const char *const body)
Definition: smtp.c:3062
struct smtp * smtp
Definition: mailx.c:66
char * body
Definition: mailx.c:76
enum smtp_status_code smtp_attachment_add_path(struct smtp *const smtp, const char *const name, const char *const path)
Definition: smtp.c:3416
#define realloc
Definition: seams.h:161
char * port
Definition: mailx.c:86
smtp_connection_security
Definition: smtp.h:140
Definition: mailx.c:62
static void mailx_address_append(struct mailx *const mailx, enum smtp_address_type address_type, const char *const email)
Definition: mailx.c:200
struct mailx_attachment * attachment_list
Definition: mailx.c:133
static void mailx_free(const struct mailx *const mailx)
Definition: mailx.c:452
size_t num_attachment
Definition: mailx.c:138
char * server
Definition: mailx.c:81
enum smtp_address_type address_type
Definition: mailx.c:34
static void mailx_init_default_values(struct mailx *const mailx)
Definition: mailx.c:439
smtp_authentication_method
Definition: smtp.h:170
static void mailx_append_attachment_arg(struct mailx *const mailx, const char *const attach_arg)
Definition: mailx.c:303
enum smtp_flag smtp_flags
Definition: mailx.c:118
static void mailx_send(struct mailx *const mailx)
Definition: mailx.c:225
enum smtp_status_code smtp_address_add(struct smtp *const smtp, enum smtp_address_type type, const char *const email, const char *const name)
Definition: smtp.c:3347
static char * smtp_ffile_get_contents(FILE *stream, size_t *bytes_read)
Definition: mailx.c:153
Definition: smtp.c:150
static void mailx_append_attachment(struct mailx *const mailx, const char *const filename, const char *const path)
Definition: mailx.c:270
SMTP client library.
smtp_flag
Definition: smtp.h:198
char name[1000]
Definition: mailx.c:50
char email[1000]
Definition: mailx.c:39
struct mailx_address * address_list
Definition: mailx.c:123
enum smtp_status_code smtp_auth(struct smtp *const smtp, enum smtp_authentication_method auth_method, const char *const user, const char *const pass)
Definition: smtp.c:3026
size_t num_address
Definition: mailx.c:128
int main(int argc, char *argv[])
Definition: mailx.c:498
char * pass
Definition: mailx.c:96
enum smtp_status_code smtp_open(const char *const server, const char *const port, enum smtp_connection_security connection_security, enum smtp_flag flags, const char *const cafile, struct smtp **smtp)
Definition: smtp.c:2987
smtp_address_type
Definition: smtp.h:105