PageRenderTime 27ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/src/lmtp_proto.c

https://bitbucket.org/vstakhov/rspamd/
C | 698 lines | 574 code | 53 blank | 71 comment | 133 complexity | 668c7f419c5604e29b9ffc563c53b420 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Copyright (c) 2009, Rambler media
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY Rambler media ''AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  20. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "config.h"
  25. #include "main.h"
  26. #include "cfg_file.h"
  27. #include "util.h"
  28. #include "lmtp.h"
  29. #include "lmtp_proto.h"
  30. /* Max line size as it is defined in rfc2822 */
  31. #define OUTBUFSIZ 1000
  32. /* LMTP commands */
  33. static f_str_t lhlo_command = {
  34. .begin = "LHLO",
  35. .len = sizeof ("LHLO") - 1
  36. };
  37. static f_str_t mail_command = {
  38. .begin = "MAIL FROM:",
  39. .len = sizeof ("MAIL FROM:") - 1
  40. };
  41. static f_str_t rcpt_command = {
  42. .begin = "RCPT TO:",
  43. .len = sizeof ("RCPT TO:") - 1
  44. };
  45. static f_str_t data_command = {
  46. .begin = "DATA",
  47. .len = sizeof ("DATA") - 1
  48. };
  49. static f_str_t data_dot = {
  50. .begin = ".\r\n",
  51. .len = sizeof (".\r\n") - 1
  52. };
  53. static const gchar *mail_regexp = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";
  54. static GRegex *mail_re = NULL;
  55. /*
  56. * Extract e-mail from read line
  57. * return <> if no valid address detected
  58. */
  59. static gchar *
  60. extract_mail (memory_pool_t * pool, f_str_t * line)
  61. {
  62. GError *err = NULL;
  63. gchar *match;
  64. GMatchInfo *info;
  65. if (mail_re == NULL) {
  66. /* Compile regexp */
  67. mail_re = g_regex_new (mail_regexp, G_REGEX_RAW, 0, &err);
  68. }
  69. if (g_regex_match_full (mail_re, line->begin, line->len, 0, 0, &info, NULL) == TRUE) {
  70. match = memory_pool_strdup (pool, g_match_info_fetch (info, 0));
  71. g_match_info_free (info);
  72. }
  73. else {
  74. match = "<>";
  75. }
  76. return match;
  77. }
  78. static gboolean
  79. out_lmtp_reply (struct worker_task *task, gint code, gchar *rcode, gchar *msg)
  80. {
  81. gchar outbuf[OUTBUFSIZ];
  82. gint r;
  83. if (*rcode == '\0') {
  84. r = rspamd_snprintf (outbuf, OUTBUFSIZ, "%d %s\r\n", code, msg);
  85. }
  86. else {
  87. r = rspamd_snprintf (outbuf, OUTBUFSIZ, "%d %s %s\r\n", code, rcode, msg);
  88. }
  89. if (! rspamd_dispatcher_write (task->dispatcher, outbuf, r, FALSE, FALSE)) {
  90. return FALSE;
  91. }
  92. return TRUE;
  93. }
  94. gint
  95. read_lmtp_input_line (struct rspamd_lmtp_proto *lmtp, f_str_t * line)
  96. {
  97. gchar *c, *rcpt;
  98. f_str_t fstr;
  99. gint i = 0, l = 0, size;
  100. switch (lmtp->state) {
  101. case LMTP_READ_LHLO:
  102. /* Search LHLO line */
  103. if ((i = fstrstri (line, &lhlo_command)) == -1) {
  104. msg_info ("LHLO expected but not found");
  105. (void)out_lmtp_reply (lmtp->task, LMTP_BAD_CMD, "5.0.0", "Need LHLO here");
  106. return -1;
  107. }
  108. else {
  109. i += lhlo_command.len;
  110. c = line->begin + i;
  111. /* Skip spaces */
  112. while (g_ascii_isspace (*c) && i < (gint)line->len) {
  113. i++;
  114. c++;
  115. }
  116. lmtp->task->helo = memory_pool_alloc (lmtp->task->task_pool, line->len - i + 1);
  117. /* Strlcpy makes string null terminated by design */
  118. rspamd_strlcpy (lmtp->task->helo, c, line->len - i + 1);
  119. lmtp->state = LMTP_READ_FROM;
  120. if (! out_lmtp_reply (lmtp->task, LMTP_OK, "", "Ok")) {
  121. return -1;
  122. }
  123. return 0;
  124. }
  125. break;
  126. case LMTP_READ_FROM:
  127. /* Search MAIL FROM: line */
  128. if ((i = fstrstri (line, &mail_command)) == -1) {
  129. msg_info ("MAIL expected but not found");
  130. (void)out_lmtp_reply (lmtp->task, LMTP_BAD_CMD, "5.0.0", "Need MAIL here");
  131. return -1;
  132. }
  133. else {
  134. i += mail_command.len;
  135. c = line->begin + i;
  136. fstr.begin = line->begin + i;
  137. fstr.len = line->len - i;
  138. lmtp->task->from = extract_mail (lmtp->task->task_pool, &fstr);
  139. lmtp->state = LMTP_READ_RCPT;
  140. if (! out_lmtp_reply (lmtp->task, LMTP_OK, "2.1.0", "Sender ok")) {
  141. return -1;
  142. }
  143. return 0;
  144. }
  145. break;
  146. case LMTP_READ_RCPT:
  147. /* Search RCPT_TO: line */
  148. if ((i = fstrstri (line, &rcpt_command)) == -1) {
  149. msg_info ("RCPT expected but not found");
  150. (void)out_lmtp_reply (lmtp->task, LMTP_NO_RCPT, "5.5.4", "Need RCPT here");
  151. return -1;
  152. }
  153. else {
  154. i += rcpt_command.len;
  155. c = line->begin + i;
  156. fstr.begin = line->begin + i;
  157. fstr.len = line->len - i;
  158. rcpt = extract_mail (lmtp->task->task_pool, &fstr);
  159. if (*rcpt == '<' && *(rcpt + 1) == '>') {
  160. /* Invalid or empty rcpt not allowed */
  161. msg_info ("bad recipient");
  162. (void)out_lmtp_reply (lmtp->task, LMTP_NO_RCPT, "5.5.4", "Bad recipient");
  163. return -1;
  164. }
  165. /* Strlcpy makes string null terminated by design */
  166. lmtp->task->rcpt = g_list_prepend (lmtp->task->rcpt, rcpt);
  167. lmtp->state = LMTP_READ_DATA;
  168. if (! out_lmtp_reply (lmtp->task, LMTP_OK, "2.1.0", "Recipient ok")) {
  169. return -1;
  170. }
  171. return 0;
  172. }
  173. break;
  174. case LMTP_READ_DATA:
  175. /* Search DATA line */
  176. if ((i = fstrstri (line, &data_command)) == -1) {
  177. msg_info ("DATA expected but not found");
  178. (void)out_lmtp_reply (lmtp->task, LMTP_BAD_CMD, "5.0.0", "Need DATA here");
  179. return -1;
  180. }
  181. else {
  182. i += data_command.len;
  183. c = line->begin + i;
  184. /* Skip spaces */
  185. while (g_ascii_isspace (*c++)) {
  186. i++;
  187. }
  188. rcpt = memory_pool_alloc (lmtp->task->task_pool, line->len - i + 1);
  189. /* Strlcpy makes string null terminated by design */
  190. rspamd_strlcpy (rcpt, c, line->len - i + 1);
  191. lmtp->task->rcpt = g_list_prepend (lmtp->task->rcpt, rcpt);
  192. lmtp->state = LMTP_READ_MESSAGE;
  193. if (! out_lmtp_reply (lmtp->task, LMTP_DATA, "", "Enter message, ending with \".\" on a line by itself")) {
  194. return -1;
  195. }
  196. lmtp->task->msg = fstralloc (lmtp->task->task_pool, BUFSIZ);
  197. return 0;
  198. }
  199. break;
  200. case LMTP_READ_MESSAGE:
  201. if (strncmp (line->begin, data_dot.begin, line->len) == 0) {
  202. lmtp->state = LMTP_READ_DOT;
  203. lmtp->task->state = READ_MESSAGE;
  204. return 0;
  205. }
  206. else {
  207. l = lmtp->task->msg->len;
  208. size = lmtp->task->msg->size;
  209. if ((gint)(l + line->len) > size) {
  210. /* Grow buffer */
  211. if ((gint)line->len > size) {
  212. size += line->len << 1;
  213. }
  214. else {
  215. /* size *= 2 */
  216. size <<= 1;
  217. }
  218. lmtp->task->msg = fstrgrow (lmtp->task->task_pool, lmtp->task->msg, size);
  219. }
  220. fstrcat (lmtp->task->msg, line);
  221. return 0;
  222. }
  223. break;
  224. case LMTP_READ_DOT:
  225. /* We have some input after reading dot, close connection as we have no currently support of multiply
  226. * messages per session
  227. */
  228. if (! out_lmtp_reply (lmtp->task, LMTP_QUIT, "", "Bye")) {
  229. return -1;
  230. }
  231. return 0;
  232. break;
  233. }
  234. return 0;
  235. }
  236. struct mta_callback_data {
  237. struct worker_task *task;
  238. rspamd_io_dispatcher_t *dispatcher;
  239. enum {
  240. LMTP_WANT_GREETING,
  241. LMTP_WANT_MAIL,
  242. LMTP_WANT_RCPT,
  243. LMTP_WANT_DATA,
  244. LMTP_WANT_DOT,
  245. LMTP_WANT_CLOSING,
  246. } state;
  247. };
  248. static gboolean
  249. parse_mta_str (f_str_t * in, struct mta_callback_data *cd)
  250. {
  251. gint r;
  252. static f_str_t okres1 = {
  253. .begin = "250 ",
  254. .len = sizeof ("250 ") - 1,
  255. }
  256. , okres2 = {
  257. .begin = "220 ",.len = sizeof ("220 ") - 1,}
  258. , datares = {
  259. .begin = "354 ",.len = sizeof ("354 ") - 1,};
  260. switch (cd->state) {
  261. case LMTP_WANT_GREETING:
  262. case LMTP_WANT_MAIL:
  263. case LMTP_WANT_RCPT:
  264. case LMTP_WANT_DATA:
  265. case LMTP_WANT_CLOSING:
  266. r = fstrstr (in, &okres1);
  267. if (r == -1) {
  268. r = fstrstr (in, &okres2);
  269. }
  270. break;
  271. case LMTP_WANT_DOT:
  272. r = fstrstr (in, &datares);
  273. break;
  274. }
  275. return r != -1;
  276. }
  277. static void
  278. close_mta_connection (struct mta_callback_data *cd, gboolean is_success)
  279. {
  280. cd->task->state = CLOSING_CONNECTION;
  281. if (is_success) {
  282. if (! out_lmtp_reply (cd->task, LMTP_OK, "", "Delivery completed")) {
  283. return;
  284. }
  285. }
  286. else {
  287. if (! out_lmtp_reply (cd->task, LMTP_FAILURE, "", "Delivery failure")) {
  288. return;
  289. }
  290. }
  291. rspamd_remove_dispatcher (cd->dispatcher);
  292. }
  293. /*
  294. * Callback that is called when there is data to read in buffer
  295. */
  296. static gboolean
  297. mta_read_socket (f_str_t * in, void *arg)
  298. {
  299. struct mta_callback_data *cd = (struct mta_callback_data *)arg;
  300. gchar outbuf[1024], *hostbuf, *c;
  301. gint hostmax, r;
  302. GList *cur;
  303. static f_str_t contres1 = {
  304. .begin = "250-",
  305. .len = sizeof ("250-") - 1,
  306. }
  307. , contres2 = {
  308. .begin = "220-",.len = sizeof ("220-") - 1,};
  309. if (fstrstr (in, &contres1) != -1 || fstrstr (in, &contres2) != -1) {
  310. /* Skip such lines */
  311. return TRUE;
  312. }
  313. switch (cd->state) {
  314. case LMTP_WANT_GREETING:
  315. if (!parse_mta_str (in, cd)) {
  316. msg_warn ("got bad greeting");
  317. close_mta_connection (cd, FALSE);
  318. return FALSE;
  319. }
  320. hostmax = sysconf (_SC_HOST_NAME_MAX) + 1;
  321. hostbuf = alloca (hostmax);
  322. gethostname (hostbuf, hostmax);
  323. hostbuf[hostmax - 1] = '\0';
  324. if (cd->task->cfg->deliver_lmtp) {
  325. r = rspamd_snprintf (outbuf, sizeof (outbuf), "LHLO %s" CRLF, hostbuf);
  326. }
  327. else {
  328. r = rspamd_snprintf (outbuf, sizeof (outbuf), "HELO %s" CRLF, hostbuf);
  329. }
  330. if (! rspamd_dispatcher_write (cd->task->dispatcher, outbuf, r, FALSE, FALSE)) {
  331. return FALSE;
  332. }
  333. cd->state = LMTP_WANT_MAIL;
  334. break;
  335. case LMTP_WANT_MAIL:
  336. if (!parse_mta_str (in, cd)) {
  337. msg_warn ("got bad helo");
  338. close_mta_connection (cd, FALSE);
  339. return FALSE;
  340. }
  341. r = rspamd_snprintf (outbuf, sizeof (outbuf), "MAIL FROM: <%s>" CRLF, cd->task->from);
  342. if (! rspamd_dispatcher_write (cd->task->dispatcher, outbuf, r, FALSE, FALSE)) {
  343. return FALSE;
  344. }
  345. cd->state = LMTP_WANT_RCPT;
  346. break;
  347. case LMTP_WANT_RCPT:
  348. if (!parse_mta_str (in, cd)) {
  349. msg_warn ("got bad mail from");
  350. close_mta_connection (cd, FALSE);
  351. return FALSE;
  352. }
  353. cur = g_list_first (cd->task->rcpt);
  354. r = 0;
  355. while (cur) {
  356. r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "RCPT TO: <%s>" CRLF, (gchar *)cur->data);
  357. cur = g_list_next (cur);
  358. }
  359. if (! rspamd_dispatcher_write (cd->task->dispatcher, outbuf, r, FALSE, FALSE)) {
  360. return FALSE;
  361. }
  362. cd->state = LMTP_WANT_DATA;
  363. break;
  364. case LMTP_WANT_DATA:
  365. if (!parse_mta_str (in, cd)) {
  366. msg_warn ("got bad rcpt");
  367. close_mta_connection (cd, FALSE);
  368. return FALSE;
  369. }
  370. r = rspamd_snprintf (outbuf, sizeof (outbuf), "DATA" CRLF);
  371. if (! rspamd_dispatcher_write (cd->task->dispatcher, outbuf, r, FALSE, FALSE)) {
  372. return FALSE;
  373. }
  374. cd->state = LMTP_WANT_DOT;
  375. break;
  376. case LMTP_WANT_DOT:
  377. if (!parse_mta_str (in, cd)) {
  378. msg_warn ("got bad data");
  379. close_mta_connection (cd, FALSE);
  380. return FALSE;
  381. }
  382. c = g_mime_object_to_string ((GMimeObject *) cd->task->message);
  383. r = strlen (c);
  384. if (! rspamd_dispatcher_write (cd->task->dispatcher, c, r, TRUE, TRUE)) {
  385. return FALSE;
  386. }
  387. memory_pool_add_destructor (cd->task->task_pool, (pool_destruct_func) g_free, c);
  388. r = rspamd_snprintf (outbuf, sizeof (outbuf), CRLF "." CRLF);
  389. if (! rspamd_dispatcher_write (cd->task->dispatcher, outbuf, r, FALSE, FALSE)) {
  390. return FALSE;
  391. }
  392. cd->state = LMTP_WANT_CLOSING;
  393. case LMTP_WANT_CLOSING:
  394. if (!parse_mta_str (in, cd)) {
  395. msg_warn ("message not delivered");
  396. close_mta_connection (cd, FALSE);
  397. return FALSE;
  398. }
  399. close_mta_connection (cd, TRUE);
  400. break;
  401. }
  402. return TRUE;
  403. }
  404. /*
  405. * Called if something goes wrong
  406. */
  407. static void
  408. mta_err_socket (GError * err, void *arg)
  409. {
  410. struct mta_callback_data *cd = (struct mta_callback_data *)arg;
  411. msg_info ("abnormaly terminating connection with MTA");
  412. close_mta_connection (cd, FALSE);
  413. }
  414. /*
  415. * Deliver mail via smtp or lmtp
  416. */
  417. static gint
  418. lmtp_deliver_mta (struct worker_task *task)
  419. {
  420. gint sock;
  421. struct sockaddr_un *un;
  422. struct mta_callback_data *cd;
  423. if (task->cfg->deliver_family == AF_UNIX) {
  424. un = alloca (sizeof (struct sockaddr_un));
  425. sock = make_unix_socket (task->cfg->deliver_host, un, FALSE, TRUE);
  426. }
  427. else {
  428. sock = make_tcp_socket (&task->cfg->deliver_addr, task->cfg->deliver_port, FALSE, TRUE);
  429. }
  430. if (sock == -1) {
  431. msg_warn ("cannot create socket for %s, %s", task->cfg->deliver_host, strerror (errno));
  432. }
  433. cd = memory_pool_alloc (task->task_pool, sizeof (struct mta_callback_data));
  434. cd->task = task;
  435. cd->state = LMTP_WANT_GREETING;
  436. cd->dispatcher = rspamd_create_dispatcher (task->ev_base, sock, BUFFER_LINE, mta_read_socket, NULL, mta_err_socket, NULL, (void *)cd);
  437. return 0;
  438. }
  439. static gchar *
  440. format_lda_args (struct worker_task *task)
  441. {
  442. gchar *res, *c, *r;
  443. size_t len;
  444. GList *rcpt;
  445. gboolean got_args = FALSE;
  446. c = task->cfg->deliver_agent_path;
  447. /* Find first arg */
  448. if ((c = strchr (c, ' ')) == NULL) {
  449. return task->cfg->deliver_agent_path;
  450. }
  451. /* Calculate length of result string */
  452. len = strlen (task->cfg->deliver_agent_path);
  453. while (*c) {
  454. if (*c == '%') {
  455. c++;
  456. switch (*c) {
  457. case 'f':
  458. /* Insert from */
  459. len += strlen (task->from) - 2;
  460. break;
  461. case 'r':
  462. /* Insert list of recipients */
  463. rcpt = g_list_first (task->rcpt);
  464. len -= 2;
  465. while (rcpt) {
  466. len += strlen ((gchar *)rcpt->data) + 1;
  467. rcpt = g_list_next (rcpt);
  468. }
  469. break;
  470. }
  471. }
  472. c++;
  473. len++;
  474. }
  475. res = memory_pool_alloc (task->task_pool, len + 1);
  476. r = res;
  477. c = task->cfg->deliver_agent_path;
  478. while (*c) {
  479. if (*c == ' ') {
  480. got_args = TRUE;
  481. }
  482. if (got_args && *c == '%') {
  483. switch (*(c + 1)) {
  484. case 'f':
  485. /* Insert from */
  486. c += 2;
  487. len = strlen (task->from);
  488. memcpy (r, task->from, len);
  489. r += len;
  490. break;
  491. case 'r':
  492. /* Insert list of recipients */
  493. c += 2;
  494. rcpt = g_list_first (task->rcpt);
  495. while (rcpt) {
  496. len = strlen ((gchar *)rcpt->data) + 1;
  497. memcpy (r, rcpt->data, len);
  498. r += len;
  499. *r++ = ' ';
  500. rcpt = g_list_next (rcpt);
  501. }
  502. break;
  503. default:
  504. *r = *c;
  505. r++;
  506. c++;
  507. break;
  508. }
  509. }
  510. else {
  511. *r = *c;
  512. r++;
  513. c++;
  514. }
  515. }
  516. return res;
  517. }
  518. static gint
  519. lmtp_deliver_lda (struct worker_task *task)
  520. {
  521. gchar *args, **argv;
  522. GMimeStream *stream;
  523. gint rc, ecode, p[2], argc;
  524. pid_t cpid, pid;
  525. if ((args = format_lda_args (task)) == NULL) {
  526. return -1;
  527. }
  528. /* Format arguments in shell style */
  529. if (!g_shell_parse_argv (args, &argc, &argv, NULL)) {
  530. msg_info ("cannot parse arguments");
  531. return -1;
  532. }
  533. if (pipe (p) == -1) {
  534. g_strfreev (argv);
  535. msg_info ("cannot open pipe: %s", strerror (errno));
  536. return -1;
  537. }
  538. /* Fork to exec LDA */
  539. #ifdef HAVE_VFORK
  540. if ((cpid = vfork ()) == -1) {
  541. g_strfreev (argv);
  542. msg_info ("cannot fork: %s", strerror (errno));
  543. return -1;
  544. }
  545. #else
  546. if ((cpid = fork ()) == -1) {
  547. g_strfreev (argv);
  548. msg_info ("cannot fork: %s", strerror (errno));
  549. return -1;
  550. }
  551. #endif
  552. if (cpid == 0) {
  553. /* Child process, close write pipe and keep only read one */
  554. close (p[1]);
  555. /* Set standart IO descriptors */
  556. if (p[0] != STDIN_FILENO) {
  557. (void)dup2 (p[0], STDIN_FILENO);
  558. (void)close (p[0]);
  559. }
  560. execv (argv[0], argv);
  561. _exit (127);
  562. }
  563. close (p[0]);
  564. stream = g_mime_stream_fs_new (p[1]);
  565. if (g_mime_object_write_to_stream ((GMimeObject *) task->message, stream) == -1) {
  566. g_strfreev (argv);
  567. msg_info ("cannot write stream to lda");
  568. return -1;
  569. }
  570. g_object_unref (stream);
  571. close (p[1]);
  572. #if defined(HAVE_WAIT4)
  573. do {
  574. pid = wait4 (cpid, &rc, 0, NULL);
  575. } while (pid == -1 && errno == EINTR);
  576. #elif defined(HAVE_WAITPID)
  577. do {
  578. pid = waitpid (cpid, &rc, 0);
  579. } while (pid == -1 && errno == EINTR);
  580. #else
  581. # error wait mechanisms are undefined
  582. #endif
  583. if (rc == -1) {
  584. g_strfreev (argv);
  585. msg_info ("lda returned error code");
  586. return -1;
  587. }
  588. else if (WIFEXITED (rc)) {
  589. ecode = WEXITSTATUS (rc);
  590. if (ecode == 0) {
  591. g_strfreev (argv);
  592. return 0;
  593. }
  594. else {
  595. g_strfreev (argv);
  596. msg_info ("lda returned error code %d", ecode);
  597. return -1;
  598. }
  599. }
  600. g_strfreev (argv);
  601. return -1;
  602. }
  603. gint
  604. lmtp_deliver_message (struct worker_task *task)
  605. {
  606. if (task->cfg->deliver_agent_path != NULL) {
  607. /* Do deliver to LDA */
  608. return lmtp_deliver_lda (task);
  609. }
  610. else {
  611. /* XXX: do lmtp/smtp client */
  612. return -1;
  613. }
  614. }
  615. gint
  616. write_lmtp_reply (struct rspamd_lmtp_proto *lmtp)
  617. {
  618. gint r;
  619. struct worker_task *task = lmtp->task;
  620. debug_task ("writing reply to client");
  621. if (lmtp->task->error_code != 0) {
  622. if (! out_lmtp_reply (lmtp->task, lmtp->task->error_code, "", lmtp->task->last_error)) {
  623. return -1;
  624. }
  625. }
  626. else {
  627. /* Do delivery */
  628. if ((r = lmtp_deliver_message (lmtp->task)) == -1) {
  629. out_lmtp_reply (lmtp->task, LMTP_FAILURE, "", "Delivery failure");
  630. return -1;
  631. }
  632. else if (r == 0) {
  633. if (! out_lmtp_reply (lmtp->task, LMTP_OK, "", "Delivery completed")) {
  634. return -1;
  635. }
  636. }
  637. else {
  638. return 1;
  639. }
  640. }
  641. return 0;
  642. }
  643. /*
  644. * vi:ts=4
  645. */