diff options
Diffstat (limited to 'libsylph/smtp.c')
| -rw-r--r-- | libsylph/smtp.c | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/libsylph/smtp.c b/libsylph/smtp.c new file mode 100644 index 0000000..da41a97 --- /dev/null +++ b/libsylph/smtp.c | |||
| @@ -0,0 +1,617 @@ | |||
| 1 | /* | ||
| 2 | * LibSylph -- E-Mail client library | ||
| 3 | * Copyright (C) 1999-2008 Hiroyuki Yamamoto | ||
| 4 | * | ||
| 5 | * This library is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; either | ||
| 8 | * version 2.1 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This library is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this library; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifdef HAVE_CONFIG_H | ||
| 21 | # include "config.h" | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #include <glib.h> | ||
| 25 | #include <glib/gi18n.h> | ||
| 26 | #include <stdio.h> | ||
| 27 | #include <string.h> | ||
| 28 | |||
| 29 | #include "smtp.h" | ||
| 30 | #include "md5_hmac.h" | ||
| 31 | #include "base64.h" | ||
| 32 | #include "utils.h" | ||
| 33 | |||
| 34 | static void smtp_session_destroy(Session *session); | ||
| 35 | |||
| 36 | static gint smtp_from(SMTPSession *session); | ||
| 37 | |||
| 38 | static gint smtp_auth(SMTPSession *session); | ||
| 39 | static gint smtp_starttls(SMTPSession *session); | ||
| 40 | static gint smtp_auth_cram_md5(SMTPSession *session); | ||
| 41 | static gint smtp_auth_plain(SMTPSession *session); | ||
| 42 | static gint smtp_auth_login(SMTPSession *session); | ||
| 43 | |||
| 44 | static gint smtp_ehlo(SMTPSession *session); | ||
| 45 | static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg); | ||
| 46 | |||
| 47 | static gint smtp_helo(SMTPSession *session); | ||
| 48 | static gint smtp_rcpt(SMTPSession *session); | ||
| 49 | static gint smtp_data(SMTPSession *session); | ||
| 50 | static gint smtp_send_data(SMTPSession *session); | ||
| 51 | /* static gint smtp_rset(SMTPSession *session); */ | ||
| 52 | static gint smtp_quit(SMTPSession *session); | ||
| 53 | static gint smtp_eom(SMTPSession *session); | ||
| 54 | |||
| 55 | static gint smtp_session_recv_msg(Session *session, const gchar *msg); | ||
| 56 | static gint smtp_session_send_data_finished(Session *session, guint len); | ||
| 57 | |||
| 58 | |||
| 59 | Session *smtp_session_new(void) | ||
| 60 | { | ||
| 61 | SMTPSession *session; | ||
| 62 | |||
| 63 | session = g_new0(SMTPSession, 1); | ||
| 64 | |||
| 65 | session_init(SESSION(session)); | ||
| 66 | |||
| 67 | SESSION(session)->type = SESSION_SMTP; | ||
| 68 | |||
| 69 | SESSION(session)->recv_msg = smtp_session_recv_msg; | ||
| 70 | |||
| 71 | SESSION(session)->recv_data_finished = NULL; | ||
| 72 | SESSION(session)->send_data_finished = smtp_session_send_data_finished; | ||
| 73 | |||
| 74 | SESSION(session)->destroy = smtp_session_destroy; | ||
| 75 | |||
| 76 | session->state = SMTP_READY; | ||
| 77 | |||
| 78 | #if USE_SSL | ||
| 79 | session->tls_init_done = FALSE; | ||
| 80 | #endif | ||
| 81 | |||
| 82 | session->hostname = NULL; | ||
| 83 | session->user = NULL; | ||
| 84 | session->pass = NULL; | ||
| 85 | |||
| 86 | session->from = NULL; | ||
| 87 | session->to_list = NULL; | ||
| 88 | session->cur_to = NULL; | ||
| 89 | |||
| 90 | session->send_data_fp = NULL; | ||
| 91 | session->send_data_len = 0; | ||
| 92 | |||
| 93 | session->avail_auth_type = 0; | ||
| 94 | session->forced_auth_type = 0; | ||
| 95 | session->auth_type = 0; | ||
| 96 | |||
| 97 | session->error_val = SM_OK; | ||
| 98 | session->error_msg = NULL; | ||
| 99 | |||
| 100 | return SESSION(session); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void smtp_session_destroy(Session *session) | ||
| 104 | { | ||
| 105 | SMTPSession *smtp_session = SMTP_SESSION(session); | ||
| 106 | |||
| 107 | g_free(smtp_session->hostname); | ||
| 108 | g_free(smtp_session->user); | ||
| 109 | g_free(smtp_session->pass); | ||
| 110 | g_free(smtp_session->from); | ||
| 111 | |||
| 112 | if (smtp_session->send_data_fp) | ||
| 113 | fclose(smtp_session->send_data_fp); | ||
| 114 | |||
| 115 | g_free(smtp_session->error_msg); | ||
| 116 | } | ||
| 117 | |||
| 118 | static gint smtp_from(SMTPSession *session) | ||
| 119 | { | ||
| 120 | gchar buf[SMTPBUFSIZE]; | ||
| 121 | |||
| 122 | g_return_val_if_fail(session->from != NULL, SM_ERROR); | ||
| 123 | |||
| 124 | session->state = SMTP_FROM; | ||
| 125 | |||
| 126 | if (strchr(session->from, '<')) | ||
| 127 | g_snprintf(buf, sizeof(buf), "MAIL FROM:%s", session->from); | ||
| 128 | else | ||
| 129 | g_snprintf(buf, sizeof(buf), "MAIL FROM:<%s>", session->from); | ||
| 130 | |||
| 131 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); | ||
| 132 | log_print("SMTP> %s\n", buf); | ||
| 133 | |||
| 134 | return SM_OK; | ||
| 135 | } | ||
| 136 | |||
| 137 | static gint smtp_auth(SMTPSession *session) | ||
| 138 | { | ||
| 139 | |||
| 140 | g_return_val_if_fail(session->user != NULL, SM_ERROR); | ||
| 141 | |||
| 142 | session->state = SMTP_AUTH; | ||
| 143 | |||
| 144 | if (session->forced_auth_type == SMTPAUTH_CRAM_MD5 || | ||
| 145 | (session->forced_auth_type == 0 && | ||
| 146 | (session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0)) | ||
| 147 | smtp_auth_cram_md5(session); | ||
| 148 | else if (session->forced_auth_type == SMTPAUTH_PLAIN || | ||
| 149 | (session->forced_auth_type == 0 && | ||
| 150 | (session->avail_auth_type & SMTPAUTH_PLAIN) != 0)) | ||
| 151 | smtp_auth_plain(session); | ||
| 152 | else if (session->forced_auth_type == SMTPAUTH_LOGIN || | ||
| 153 | (session->forced_auth_type == 0 && | ||
| 154 | (session->avail_auth_type & SMTPAUTH_LOGIN) != 0)) | ||
| 155 | smtp_auth_login(session); | ||
| 156 | else { | ||
| 157 | log_warning(_("SMTP AUTH not available\n")); | ||
| 158 | return SM_AUTHFAIL; | ||
| 159 | } | ||
| 160 | |||
| 161 | return SM_OK; | ||
| 162 | } | ||
| 163 | |||
| 164 | static gint smtp_auth_recv(SMTPSession *session, const gchar *msg) | ||
| 165 | { | ||
| 166 | gchar buf[SMTPBUFSIZE]; | ||
| 167 | |||
| 168 | switch (session->auth_type) { | ||
| 169 | case SMTPAUTH_LOGIN: | ||
| 170 | session->state = SMTP_AUTH_LOGIN_USER; | ||
| 171 | |||
| 172 | if (!strncmp(msg, "334 ", 4)) { | ||
| 173 | base64_encode(buf, (guchar *)session->user, | ||
| 174 | strlen(session->user)); | ||
| 175 | |||
| 176 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, | ||
| 177 | buf); | ||
| 178 | log_print("ESMTP> [USERID]\n"); | ||
| 179 | } else { | ||
| 180 | /* Server rejects AUTH */ | ||
| 181 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, | ||
| 182 | "*"); | ||
| 183 | log_print("ESMTP> *\n"); | ||
| 184 | } | ||
| 185 | break; | ||
| 186 | case SMTPAUTH_CRAM_MD5: | ||
| 187 | session->state = SMTP_AUTH_CRAM_MD5; | ||
| 188 | |||
| 189 | if (!strncmp(msg, "334 ", 4)) { | ||
| 190 | gchar *response; | ||
| 191 | gchar *response64; | ||
| 192 | guchar *challenge; | ||
| 193 | gint challengelen; | ||
| 194 | gchar hexdigest[33]; | ||
| 195 | |||
| 196 | challenge = g_malloc(strlen(msg + 4) + 1); | ||
| 197 | challengelen = base64_decode(challenge, msg + 4, -1); | ||
| 198 | challenge[challengelen] = '\0'; | ||
| 199 | log_print("ESMTP< [Decoded: %s]\n", challenge); | ||
| 200 | |||
| 201 | g_snprintf(buf, sizeof(buf), "%s", session->pass); | ||
| 202 | md5_hex_hmac(hexdigest, challenge, challengelen, | ||
| 203 | (guchar *)buf, strlen(buf)); | ||
| 204 | g_free(challenge); | ||
| 205 | |||
| 206 | response = g_strdup_printf | ||
| 207 | ("%s %s", session->user, hexdigest); | ||
| 208 | log_print("ESMTP> [Encoded: %s]\n", response); | ||
| 209 | |||
| 210 | response64 = g_malloc((strlen(response) + 3) * 2 + 1); | ||
| 211 | base64_encode(response64, (guchar *)response, | ||
| 212 | strlen(response)); | ||
| 213 | g_free(response); | ||
| 214 | |||
| 215 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, | ||
| 216 | response64); | ||
| 217 | log_print("ESMTP> %s\n", response64); | ||
| 218 | g_free(response64); | ||
| 219 | } else { | ||
| 220 | /* Server rejects AUTH */ | ||
| 221 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, | ||
| 222 | "*"); | ||
| 223 | log_print("ESMTP> *\n"); | ||
| 224 | } | ||
| 225 | break; | ||
| 226 | case SMTPAUTH_DIGEST_MD5: | ||
| 227 | default: | ||
| 228 | /* stop smtp_auth when no correct authtype */ | ||
| 229 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*"); | ||
| 230 | log_print("ESMTP> *\n"); | ||
| 231 | break; | ||
| 232 | } | ||
| 233 | |||
| 234 | return SM_OK; | ||
| 235 | } | ||
| 236 | |||
| 237 | static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg) | ||
| 238 | { | ||
| 239 | gchar buf[SMTPBUFSIZE]; | ||
| 240 | |||
| 241 | session->state = SMTP_AUTH_LOGIN_PASS; | ||
| 242 | |||
| 243 | if (!strncmp(msg, "334 ", 4)) | ||
| 244 | base64_encode(buf, (guchar *)session->pass, | ||
| 245 | strlen(session->pass)); | ||
| 246 | else | ||
| 247 | /* Server rejects AUTH */ | ||
| 248 | g_snprintf(buf, sizeof(buf), "*"); | ||
| 249 | |||
| 250 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); | ||
| 251 | log_print("ESMTP> [PASSWORD]\n"); | ||
| 252 | |||
| 253 | return SM_OK; | ||
| 254 | } | ||
| 255 | |||
| 256 | static gint smtp_ehlo(SMTPSession *session) | ||
| 257 | { | ||
| 258 | gchar buf[SMTPBUFSIZE]; | ||
| 259 | |||
| 260 | session->state = SMTP_EHLO; | ||
| 261 | |||
| 262 | session->avail_auth_type = 0; | ||
| 263 | |||
| 264 | g_snprintf(buf, sizeof(buf), "EHLO %s", | ||
| 265 | session->hostname ? session->hostname : get_domain_name()); | ||
| 266 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); | ||
| 267 | log_print("ESMTP> %s\n", buf); | ||
| 268 | |||
| 269 | return SM_OK; | ||
| 270 | } | ||
| 271 | |||
| 272 | static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg) | ||
| 273 | { | ||
| 274 | if (strncmp(msg, "250", 3) == 0) { | ||
| 275 | const gchar *p = msg; | ||
| 276 | p += 3; | ||
| 277 | if (*p == '-' || *p == ' ') p++; | ||
| 278 | if (g_ascii_strncasecmp(p, "AUTH", 4) == 0 && p[4] != '\0') { | ||
| 279 | p += 5; | ||
| 280 | if (strcasestr(p, "PLAIN")) | ||
| 281 | session->avail_auth_type |= SMTPAUTH_PLAIN; | ||
| 282 | if (strcasestr(p, "LOGIN")) | ||
| 283 | session->avail_auth_type |= SMTPAUTH_LOGIN; | ||
| 284 | if (strcasestr(p, "CRAM-MD5")) | ||
| 285 | session->avail_auth_type |= SMTPAUTH_CRAM_MD5; | ||
| 286 | if (strcasestr(p, "DIGEST-MD5")) | ||
| 287 | session->avail_auth_type |= SMTPAUTH_DIGEST_MD5; | ||
| 288 | } | ||
| 289 | return SM_OK; | ||
| 290 | } else if ((msg[0] == '1' || msg[0] == '2' || msg[0] == '3') && | ||
| 291 | (msg[3] == ' ' || msg[3] == '\0')) | ||
| 292 | return SM_OK; | ||
| 293 | else if (msg[0] == '5' && msg[1] == '0' && | ||
| 294 | (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) | ||
| 295 | return SM_ERROR; | ||
| 296 | |||
| 297 | return SM_ERROR; | ||
| 298 | } | ||
| 299 | |||
| 300 | static gint smtp_starttls(SMTPSession *session) | ||
| 301 | { | ||
| 302 | session->state = SMTP_STARTTLS; | ||
| 303 | |||
| 304 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "STARTTLS"); | ||
| 305 | log_print("ESMTP> STARTTLS\n"); | ||
| 306 | |||
| 307 | return SM_OK; | ||
| 308 | } | ||
| 309 | |||
| 310 | static gint smtp_auth_cram_md5(SMTPSession *session) | ||
| 311 | { | ||
| 312 | session->state = SMTP_AUTH; | ||
| 313 | session->auth_type = SMTPAUTH_CRAM_MD5; | ||
| 314 | |||
| 315 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH CRAM-MD5"); | ||
| 316 | log_print("ESMTP> AUTH CRAM-MD5\n"); | ||
| 317 | |||
| 318 | return SM_OK; | ||
| 319 | } | ||
| 320 | |||
| 321 | static gint smtp_auth_plain(SMTPSession *session) | ||
| 322 | { | ||
| 323 | gchar *authstr; | ||
| 324 | gint authlen; | ||
| 325 | gchar *outbuf; | ||
| 326 | gchar *p; | ||
| 327 | |||
| 328 | session->state = SMTP_AUTH_PLAIN; | ||
| 329 | session->auth_type = SMTPAUTH_PLAIN; | ||
| 330 | |||
| 331 | /* | ||
| 332 | * construct the string: \0<user>\0<pass> | ||
| 333 | */ | ||
| 334 | |||
| 335 | authlen = 1 + strlen(session->user) + 1 + strlen(session->pass); | ||
| 336 | authstr = g_malloc(authlen + 1); | ||
| 337 | |||
| 338 | p = authstr; | ||
| 339 | |||
| 340 | *p++ = '\0'; | ||
| 341 | strcpy(p, session->user); | ||
| 342 | p += strlen(p) + 1; | ||
| 343 | strcpy(p, session->pass); | ||
| 344 | |||
| 345 | outbuf = g_malloc(sizeof("AUTH PLAIN ") + authlen * 2 + 1); | ||
| 346 | |||
| 347 | strcpy(outbuf, "AUTH PLAIN "); | ||
| 348 | p = outbuf + strlen(outbuf); | ||
| 349 | base64_encode(p, (guchar *)authstr, authlen); | ||
| 350 | |||
| 351 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, outbuf); | ||
| 352 | log_print("ESMTP> AUTH PLAIN ********\n"); | ||
| 353 | |||
| 354 | g_free(outbuf); | ||
| 355 | g_free(authstr); | ||
| 356 | |||
| 357 | return SM_OK; | ||
| 358 | } | ||
| 359 | |||
| 360 | static gint smtp_auth_login(SMTPSession *session) | ||
| 361 | { | ||
| 362 | session->state = SMTP_AUTH; | ||
| 363 | session->auth_type = SMTPAUTH_LOGIN; | ||
| 364 | |||
| 365 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH LOGIN"); | ||
| 366 | log_print("ESMTP> AUTH LOGIN\n"); | ||
| 367 | |||
| 368 | return SM_OK; | ||
| 369 | } | ||
| 370 | |||
| 371 | static gint smtp_helo(SMTPSession *session) | ||
| 372 | { | ||
| 373 | gchar buf[SMTPBUFSIZE]; | ||
| 374 | |||
| 375 | session->state = SMTP_HELO; | ||
| 376 | |||
| 377 | g_snprintf(buf, sizeof(buf), "HELO %s", | ||
| 378 | session->hostname ? session->hostname : get_domain_name()); | ||
| 379 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); | ||
| 380 | log_print("SMTP> %s\n", buf); | ||
| 381 | |||
| 382 | return SM_OK; | ||
| 383 | } | ||
| 384 | |||
| 385 | static gint smtp_rcpt(SMTPSession *session) | ||
| 386 | { | ||
| 387 | gchar buf[SMTPBUFSIZE]; | ||
| 388 | gchar *to; | ||
| 389 | |||
| 390 | g_return_val_if_fail(session->cur_to != NULL, SM_ERROR); | ||
| 391 | |||
| 392 | session->state = SMTP_RCPT; | ||
| 393 | |||
| 394 | to = (gchar *)session->cur_to->data; | ||
| 395 | |||
| 396 | if (strchr(to, '<')) | ||
| 397 | g_snprintf(buf, sizeof(buf), "RCPT TO:%s", to); | ||
| 398 | else | ||
| 399 | g_snprintf(buf, sizeof(buf), "RCPT TO:<%s>", to); | ||
| 400 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); | ||
| 401 | log_print("SMTP> %s\n", buf); | ||
| 402 | |||
| 403 | session->cur_to = session->cur_to->next; | ||
| 404 | |||
| 405 | return SM_OK; | ||
| 406 | } | ||
| 407 | |||
| 408 | static gint smtp_data(SMTPSession *session) | ||
| 409 | { | ||
| 410 | session->state = SMTP_DATA; | ||
| 411 | |||
| 412 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "DATA"); | ||
| 413 | log_print("SMTP> DATA\n"); | ||
| 414 | |||
| 415 | return SM_OK; | ||
| 416 | } | ||
| 417 | |||
| 418 | static gint smtp_send_data(SMTPSession *session) | ||
| 419 | { | ||
| 420 | session->state = SMTP_SEND_DATA; | ||
| 421 | |||
| 422 | session_send_data(SESSION(session), session->send_data_fp, | ||
| 423 | session->send_data_len); | ||
| 424 | |||
| 425 | return SM_OK; | ||
| 426 | } | ||
| 427 | |||
| 428 | #if 0 | ||
| 429 | static gint smtp_rset(SMTPSession *session) | ||
| 430 | { | ||
| 431 | session->state = SMTP_RSET; | ||
| 432 | |||
| 433 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "RSET"); | ||
| 434 | log_print("SMTP> RSET\n"); | ||
| 435 | |||
| 436 | return SM_OK; | ||
| 437 | } | ||
| 438 | #endif | ||
| 439 | |||
| 440 | static gint smtp_quit(SMTPSession *session) | ||
| 441 | { | ||
| 442 | session->state = SMTP_QUIT; | ||
| 443 | |||
| 444 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "QUIT"); | ||
| 445 | log_print("SMTP> QUIT\n"); | ||
| 446 | |||
| 447 | return SM_OK; | ||
| 448 | } | ||
| 449 | |||
| 450 | static gint smtp_eom(SMTPSession *session) | ||
| 451 | { | ||
| 452 | session->state = SMTP_EOM; | ||
| 453 | |||
| 454 | session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "."); | ||
| 455 | log_print("SMTP> . (EOM)\n"); | ||
| 456 | |||
| 457 | return SM_OK; | ||
| 458 | } | ||
| 459 | |||
| 460 | static gint smtp_session_recv_msg(Session *session, const gchar *msg) | ||
| 461 | { | ||
| 462 | SMTPSession *smtp_session = SMTP_SESSION(session); | ||
| 463 | gboolean cont = FALSE; | ||
| 464 | |||
| 465 | if (strlen(msg) < 4) { | ||
| 466 | log_warning(_("bad SMTP response\n")); | ||
| 467 | return -1; | ||
| 468 | } | ||
| 469 | |||
| 470 | switch (smtp_session->state) { | ||
| 471 | case SMTP_EHLO: | ||
| 472 | case SMTP_STARTTLS: | ||
| 473 | case SMTP_AUTH: | ||
| 474 | case SMTP_AUTH_PLAIN: | ||
| 475 | case SMTP_AUTH_LOGIN_USER: | ||
| 476 | case SMTP_AUTH_LOGIN_PASS: | ||
| 477 | case SMTP_AUTH_CRAM_MD5: | ||
| 478 | log_print("ESMTP< %s\n", msg); | ||
| 479 | break; | ||
| 480 | default: | ||
| 481 | log_print("SMTP< %s\n", msg); | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | |||
| 485 | if (msg[0] == '5' && msg[1] == '0' && | ||
| 486 | (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) { | ||
| 487 | log_warning(_("error occurred on SMTP session\n")); | ||
| 488 | smtp_session->state = SMTP_ERROR; | ||
| 489 | smtp_session->error_val = SM_ERROR; | ||
| 490 | g_free(smtp_session->error_msg); | ||
| 491 | smtp_session->error_msg = g_strdup(msg); | ||
| 492 | return -1; | ||
| 493 | } | ||
| 494 | |||
| 495 | if (!strncmp(msg, "535", 3)) { | ||
| 496 | log_warning(_("error occurred on authentication\n")); | ||
| 497 | smtp_session->state = SMTP_ERROR; | ||
| 498 | smtp_session->error_val = SM_AUTHFAIL; | ||
| 499 | g_free(smtp_session->error_msg); | ||
| 500 | smtp_session->error_msg = g_strdup(msg); | ||
| 501 | return -1; | ||
| 502 | } | ||
| 503 | |||
| 504 | if (msg[0] != '1' && msg[0] != '2' && msg[0] != '3') { | ||
| 505 | log_warning(_("error occurred on SMTP session\n")); | ||
| 506 | smtp_session->state = SMTP_ERROR; | ||
| 507 | smtp_session->error_val = SM_ERROR; | ||
| 508 | g_free(smtp_session->error_msg); | ||
| 509 | smtp_session->error_msg = g_strdup(msg); | ||
| 510 | return -1; | ||
| 511 | } | ||
| 512 | |||
| 513 | if (msg[3] == '-') | ||
| 514 | cont = TRUE; | ||
| 515 | else if (msg[3] != ' ' && msg[3] != '\0') { | ||
| 516 | log_warning(_("bad SMTP response\n")); | ||
| 517 | smtp_session->state = SMTP_ERROR; | ||
| 518 | smtp_session->error_val = SM_UNRECOVERABLE; | ||
| 519 | return -1; | ||
| 520 | } | ||
| 521 | |||
| 522 | /* ignore all multiline responses except for EHLO */ | ||
| 523 | if (cont && smtp_session->state != SMTP_EHLO) | ||
| 524 | return session_recv_msg(session); | ||
| 525 | |||
| 526 | switch (smtp_session->state) { | ||
| 527 | case SMTP_READY: | ||
| 528 | case SMTP_CONNECTED: | ||
| 529 | #if USE_SSL | ||
| 530 | if (smtp_session->user || session->ssl_type != SSL_NONE) | ||
| 531 | #else | ||
| 532 | if (smtp_session->user) | ||
| 533 | #endif | ||
| 534 | smtp_ehlo(smtp_session); | ||
| 535 | else | ||
| 536 | smtp_helo(smtp_session); | ||
| 537 | break; | ||
| 538 | case SMTP_HELO: | ||
| 539 | smtp_from(smtp_session); | ||
| 540 | break; | ||
| 541 | case SMTP_EHLO: | ||
| 542 | smtp_ehlo_recv(smtp_session, msg); | ||
| 543 | if (cont == TRUE) | ||
| 544 | break; | ||
| 545 | #if USE_SSL | ||
| 546 | if (session->ssl_type == SSL_STARTTLS && | ||
| 547 | smtp_session->tls_init_done == FALSE) { | ||
| 548 | smtp_starttls(smtp_session); | ||
| 549 | break; | ||
| 550 | } | ||
| 551 | #endif | ||
| 552 | if (smtp_session->user) { | ||
| 553 | if (smtp_auth(smtp_session) != SM_OK) | ||
| 554 | smtp_from(smtp_session); | ||
| 555 | } else | ||
| 556 | smtp_from(smtp_session); | ||
| 557 | break; | ||
| 558 | case SMTP_STARTTLS: | ||
| 559 | #if USE_SSL | ||
| 560 | if (session_start_tls(session) < 0) { | ||
| 561 | log_warning(_("can't start TLS session\n")); | ||
| 562 | smtp_session->state = SMTP_ERROR; | ||
| 563 | smtp_session->error_val = SM_ERROR; | ||
| 564 | return -1; | ||
| 565 | } | ||
| 566 | smtp_session->tls_init_done = TRUE; | ||
| 567 | smtp_ehlo(smtp_session); | ||
| 568 | #endif | ||
| 569 | break; | ||
| 570 | case SMTP_AUTH: | ||
| 571 | smtp_auth_recv(smtp_session, msg); | ||
| 572 | break; | ||
| 573 | case SMTP_AUTH_LOGIN_USER: | ||
| 574 | smtp_auth_login_user_recv(smtp_session, msg); | ||
| 575 | break; | ||
| 576 | case SMTP_AUTH_PLAIN: | ||
| 577 | case SMTP_AUTH_LOGIN_PASS: | ||
| 578 | case SMTP_AUTH_CRAM_MD5: | ||
| 579 | smtp_from(smtp_session); | ||
| 580 | break; | ||
| 581 | case SMTP_FROM: | ||
| 582 | if (smtp_session->cur_to) | ||
| 583 | smtp_rcpt(smtp_session); | ||
| 584 | break; | ||
| 585 | case SMTP_RCPT: | ||
| 586 | if (smtp_session->cur_to) | ||
| 587 | smtp_rcpt(smtp_session); | ||
| 588 | else | ||
| 589 | smtp_data(smtp_session); | ||
| 590 | break; | ||
| 591 | case SMTP_DATA: | ||
| 592 | smtp_send_data(smtp_session); | ||
| 593 | break; | ||
| 594 | case SMTP_EOM: | ||
| 595 | smtp_quit(smtp_session); | ||
| 596 | break; | ||
| 597 | case SMTP_QUIT: | ||
| 598 | session_disconnect(session); | ||
| 599 | break; | ||
| 600 | case SMTP_ERROR: | ||
| 601 | default: | ||
| 602 | log_warning(_("error occurred on SMTP session\n")); | ||
| 603 | smtp_session->error_val = SM_ERROR; | ||
| 604 | return -1; | ||
| 605 | } | ||
| 606 | |||
| 607 | if (cont) | ||
| 608 | return session_recv_msg(session); | ||
| 609 | |||
| 610 | return 0; | ||
| 611 | } | ||
| 612 | |||
| 613 | static gint smtp_session_send_data_finished(Session *session, guint len) | ||
| 614 | { | ||
| 615 | smtp_eom(SMTP_SESSION(session)); | ||
| 616 | return 0; | ||
| 617 | } | ||
