diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | activitypub.c | 3 | ||||
| -rw-r--r-- | tests/smtp.c | 24 | ||||
| -rw-r--r-- | utils.c | 9 | ||||
| -rw-r--r-- | xs_curl.h | 22 |
5 files changed, 51 insertions, 10 deletions
| @@ -1,2 +1,3 @@ | |||
| 1 | *.o | 1 | **/*.o |
| 2 | tests/smtp | ||
| 2 | snac | 3 | snac |
diff --git a/activitypub.c b/activitypub.c index 4cb779a..f3b2bae 100644 --- a/activitypub.c +++ b/activitypub.c | |||
| @@ -2538,8 +2538,9 @@ int send_email(const xs_dict *mailinfo) | |||
| 2538 | *from = xs_dict_get(mailinfo, "from"), | 2538 | *from = xs_dict_get(mailinfo, "from"), |
| 2539 | *to = xs_dict_get(mailinfo, "to"), | 2539 | *to = xs_dict_get(mailinfo, "to"), |
| 2540 | *body = xs_dict_get(mailinfo, "body"); | 2540 | *body = xs_dict_get(mailinfo, "body"); |
| 2541 | int smtp_port = parse_port(url, NULL); | ||
| 2541 | 2542 | ||
| 2542 | return xs_smtp_request(url, user, pass, from, to, body); | 2543 | return xs_smtp_request(url, user, pass, from, to, body, smtp_port == 465 || smtp_port == 587); |
| 2543 | } | 2544 | } |
| 2544 | 2545 | ||
| 2545 | 2546 | ||
diff --git a/tests/smtp.c b/tests/smtp.c new file mode 100644 index 0000000..1100a9d --- /dev/null +++ b/tests/smtp.c | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | ||
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | ||
| 3 | |||
| 4 | #define XS_IMPLEMENTATION | ||
| 5 | #include "../xs.h" | ||
| 6 | #include "../xs_curl.h" | ||
| 7 | |||
| 8 | #define FROM "<snac-smtp-test@locahost>" | ||
| 9 | |||
| 10 | int main(void) { | ||
| 11 | xs *to = xs_fmt("<%s@localhost>", getenv("USER")), | ||
| 12 | *body = xs_fmt("" | ||
| 13 | "To: %s \r\n" | ||
| 14 | "From: " FROM "\r\n" | ||
| 15 | "Subject: snac smtp test\r\n" | ||
| 16 | "\r\n" | ||
| 17 | "If you read this as an email, it probably worked!\r\n", | ||
| 18 | to); | ||
| 19 | |||
| 20 | return xs_smtp_request("smtp://localhost", NULL, NULL, | ||
| 21 | FROM, | ||
| 22 | to, | ||
| 23 | body, 0); | ||
| 24 | } \ No newline at end of file | ||
| @@ -931,6 +931,7 @@ int parse_port(const char *url, const char **errstr) | |||
| 931 | if (!(col = strchr(url, ':'))) { | 931 | if (!(col = strchr(url, ':'))) { |
| 932 | if (errstr) | 932 | if (errstr) |
| 933 | *errstr = "bad url"; | 933 | *errstr = "bad url"; |
| 934 | |||
| 934 | return -1; | 935 | return -1; |
| 935 | } | 936 | } |
| 936 | 937 | ||
| @@ -950,13 +951,17 @@ int parse_port(const char *url, const char **errstr) | |||
| 950 | if (ret != -1) | 951 | if (ret != -1) |
| 951 | return ret; | 952 | return ret; |
| 952 | 953 | ||
| 953 | *errstr = strerror(errno); | 954 | if (errstr) |
| 955 | *errstr = strerror(errno); | ||
| 956 | |||
| 954 | return -1; | 957 | return -1; |
| 955 | } | 958 | } |
| 956 | 959 | ||
| 957 | return tmp; | 960 | return tmp; |
| 958 | } | 961 | } |
| 959 | 962 | ||
| 960 | *errstr = "unknown protocol"; | 963 | if (errstr) |
| 964 | *errstr = "unknown protocol"; | ||
| 965 | |||
| 961 | return -1; | 966 | return -1; |
| 962 | } | 967 | } |
| @@ -10,7 +10,8 @@ xs_dict *xs_http_request(const char *method, const char *url, | |||
| 10 | xs_str **payload, int *p_size, int timeout); | 10 | xs_str **payload, int *p_size, int timeout); |
| 11 | 11 | ||
| 12 | int xs_smtp_request(const char *url, const char *user, const char *pass, | 12 | int xs_smtp_request(const char *url, const char *user, const char *pass, |
| 13 | const char *from, const char *to, const xs_str *body); | 13 | const char *from, const char *to, const xs_str *body, |
| 14 | int use_ssl); | ||
| 14 | 15 | ||
| 15 | #ifdef XS_IMPLEMENTATION | 16 | #ifdef XS_IMPLEMENTATION |
| 16 | 17 | ||
| @@ -198,7 +199,8 @@ xs_dict *xs_http_request(const char *method, const char *url, | |||
| 198 | } | 199 | } |
| 199 | 200 | ||
| 200 | int xs_smtp_request(const char *url, const char *user, const char *pass, | 201 | int xs_smtp_request(const char *url, const char *user, const char *pass, |
| 201 | const char *from, const char *to, const xs_str *body) | 202 | const char *from, const char *to, const xs_str *body, |
| 203 | int use_ssl) | ||
| 202 | { | 204 | { |
| 203 | CURL *curl; | 205 | CURL *curl; |
| 204 | CURLcode res = CURLE_OK; | 206 | CURLcode res = CURLE_OK; |
| @@ -212,11 +214,19 @@ int xs_smtp_request(const char *url, const char *user, const char *pass, | |||
| 212 | curl = curl_easy_init(); | 214 | curl = curl_easy_init(); |
| 213 | 215 | ||
| 214 | curl_easy_setopt(curl, CURLOPT_URL, url); | 216 | curl_easy_setopt(curl, CURLOPT_URL, url); |
| 215 | curl_easy_setopt(curl, CURLOPT_USERNAME, user); | 217 | if (user && pass) { |
| 216 | curl_easy_setopt(curl, CURLOPT_PASSWORD, pass); | 218 | /* allow authless connections, to, e.g. localhost */ |
| 219 | curl_easy_setopt(curl, CURLOPT_USERNAME, user); | ||
| 220 | curl_easy_setopt(curl, CURLOPT_PASSWORD, pass); | ||
| 221 | } | ||
| 222 | |||
| 223 | if (use_ssl) | ||
| 224 | curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); | ||
| 217 | 225 | ||
| 218 | curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from); | 226 | curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from); |
| 219 | curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt = curl_slist_append(rcpt, to)); | 227 | |
| 228 | rcpt = curl_slist_append(rcpt, to); | ||
| 229 | curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt); | ||
| 220 | 230 | ||
| 221 | curl_easy_setopt(curl, CURLOPT_READDATA, &pd); | 231 | curl_easy_setopt(curl, CURLOPT_READDATA, &pd); |
| 222 | curl_easy_setopt(curl, CURLOPT_READFUNCTION, _post_callback); | 232 | curl_easy_setopt(curl, CURLOPT_READFUNCTION, _post_callback); |
| @@ -224,8 +234,8 @@ int xs_smtp_request(const char *url, const char *user, const char *pass, | |||
| 224 | 234 | ||
| 225 | res = curl_easy_perform(curl); | 235 | res = curl_easy_perform(curl); |
| 226 | 236 | ||
| 227 | curl_slist_free_all(rcpt); | ||
| 228 | curl_easy_cleanup(curl); | 237 | curl_easy_cleanup(curl); |
| 238 | curl_slist_free_all(rcpt); | ||
| 229 | 239 | ||
| 230 | return (int)res; | 240 | return (int)res; |
| 231 | } | 241 | } |