send_message.c (19077B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program 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 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include "defs.h" 21 22 #include <glib.h> 23 #include <glib/gi18n.h> 24 #include <gtk/gtk.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <signal.h> 28 #include <sys/types.h> 29 #include <sys/wait.h> 30 31 #include "send_message.h" 32 #include "session.h" 33 #include "ssl.h" 34 #include "smtp.h" 35 #include "prefs_common.h" 36 #include "prefs_account.h" 37 #include "procheader.h" 38 #include "account.h" 39 #include "progressdialog.h" 40 #include "statusbar.h" 41 #include "inputdialog.h" 42 #include "alertpanel.h" 43 #include "manage_window.h" 44 #include "logwindow.h" 45 #include "socket.h" 46 #include "utils.h" 47 #include "gtkutils.h" 48 #include "inc.h" 49 #include "log.h" 50 #include "passwordstore.h" 51 52 typedef struct _SendProgressDialog SendProgressDialog; 53 54 struct _SendProgressDialog 55 { 56 ProgressDialog *dialog; 57 Session *session; 58 gboolean cancelled; 59 }; 60 61 static SendProgressDialog *send_dialog = NULL; 62 63 static gint send_recv_message (Session *session, 64 const gchar *msg, 65 gpointer data); 66 static gint send_send_data_progressive (Session *session, 67 guint cur_len, 68 guint total_len, 69 gpointer data); 70 static gint send_send_data_finished (Session *session, 71 guint len, 72 gpointer data); 73 74 static SendProgressDialog *send_progress_dialog_create(void); 75 static void send_progress_dialog_destroy(SendProgressDialog *dialog); 76 77 static void send_showlog_button_cb (GtkWidget *widget, 78 gpointer data); 79 static void send_cancel_button_cb (GtkWidget *widget, 80 gpointer data); 81 82 static void send_put_error (Session *session); 83 84 85 void send_cancel(void) 86 { 87 if (send_dialog) 88 send_cancel_button_cb(NULL, send_dialog); 89 } 90 91 gboolean send_is_active(void) 92 { 93 return (send_dialog != NULL); 94 } 95 96 gint send_message(const gchar *file, PrefsAccount *ac_prefs, GSList *to_list) 97 { 98 FILE *fp; 99 gint val; 100 101 cm_return_val_if_fail(file != NULL, -1); 102 cm_return_val_if_fail(ac_prefs != NULL, -1); 103 cm_return_val_if_fail(to_list != NULL, -1); 104 105 if ((fp = g_fopen(file, "rb")) == NULL) { 106 FILE_OP_ERROR(file, "g_fopen"); 107 return -1; 108 } 109 110 inc_lock(); 111 if (ac_prefs->use_mail_command && ac_prefs->mail_command && 112 (*ac_prefs->mail_command)) { 113 val = send_message_local(ac_prefs->mail_command, fp); 114 fclose(fp); 115 inc_unlock(); 116 return val; 117 } else { 118 val = send_message_smtp(ac_prefs, to_list, fp); 119 120 fclose(fp); 121 inc_unlock(); 122 return val; 123 } 124 } 125 126 enum 127 { 128 Q_SENDER = 0, 129 Q_SMTPSERVER = 1, 130 Q_RECIPIENTS = 2, 131 Q_ACCOUNT_ID = 3 132 }; 133 134 gint send_message_local(const gchar *command, FILE *fp) 135 { 136 gchar **argv; 137 GPid pid; 138 gint child_stdin; 139 gchar buf[BUFFSIZE]; 140 gboolean err = FALSE; 141 142 cm_return_val_if_fail(command != NULL, -1); 143 cm_return_val_if_fail(fp != NULL, -1); 144 145 log_message(LOG_PROTOCOL, _("Sending message using command: %s\n"), command); 146 147 argv = strsplit_with_quote(command, " ", 0); 148 149 if (g_spawn_async_with_pipes(NULL, argv, NULL, 150 G_SPAWN_DO_NOT_REAP_CHILD, 151 NULL, NULL, 152 &pid, &child_stdin, NULL, NULL, 153 NULL) == FALSE) { 154 g_snprintf(buf, sizeof(buf), 155 _("Couldn't execute command: %s"), command); 156 log_warning(LOG_PROTOCOL, "%s\n", buf); 157 alertpanel_error("%s", buf); 158 g_strfreev(argv); 159 return -1; 160 } 161 g_strfreev(argv); 162 163 while (fgets(buf, sizeof(buf), fp) != NULL) { 164 strretchomp(buf); 165 if (buf[0] == '.' && buf[1] == '\0') { 166 if (fd_write_all(child_stdin, ".", 1) < 0) { 167 err = TRUE; 168 break; 169 } 170 } 171 if (fd_write_all(child_stdin, buf, strlen(buf)) < 0 || 172 fd_write_all(child_stdin, "\n", 1) < 0) { 173 err = TRUE; 174 break; 175 } 176 } 177 178 close(child_stdin); 179 180 gint status; 181 waitpid(pid, &status, 0); 182 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 183 err = TRUE; 184 185 g_spawn_close_pid(pid); 186 187 if (err) { 188 g_snprintf(buf, sizeof(buf), 189 _("Error occurred while executing command: %s"), 190 command); 191 log_warning(LOG_PROTOCOL, "%s\n", buf); 192 alertpanel_error("%s", buf); 193 return -1; 194 } 195 196 return 0; 197 } 198 199 gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, gboolean keep_session) 200 { 201 Session *session; 202 SMTPSession *smtp_session; 203 gushort port = 0; 204 gchar buf[BUFFSIZE]; 205 gint ret = 0; 206 gboolean was_inited = FALSE; 207 MsgInfo *tmp_msginfo = NULL; 208 MsgFlags flags = {0, 0}; 209 long fp_pos = 0; 210 gchar spec_from[BUFFSIZE]; 211 212 cm_return_val_if_fail(ac_prefs != NULL, -1); 213 cm_return_val_if_fail(ac_prefs->address != NULL, -1); 214 cm_return_val_if_fail(ac_prefs->smtp_server != NULL, -1); 215 cm_return_val_if_fail(to_list != NULL, -1); 216 cm_return_val_if_fail(fp != NULL, -1); 217 218 /* get the From address used, not necessarily the ac_prefs', 219 * because it's editable. */ 220 221 fp_pos = ftell(fp); 222 if (fp_pos < 0) { 223 perror("ftell"); 224 return -1; 225 } 226 tmp_msginfo = procheader_parse_stream(fp, flags, TRUE, FALSE); 227 if (fseek(fp, fp_pos, SEEK_SET) < 0) { 228 perror("fseek"); 229 return -1; 230 } 231 232 if (tmp_msginfo && tmp_msginfo->extradata && tmp_msginfo->extradata->resent_from) { 233 strncpy2(spec_from, tmp_msginfo->extradata->resent_from, BUFFSIZE-1); 234 extract_address(spec_from); 235 } else if (tmp_msginfo && tmp_msginfo->from) { 236 strncpy2(spec_from, tmp_msginfo->from, BUFFSIZE-1); 237 extract_address(spec_from); 238 } else { 239 strncpy2(spec_from, ac_prefs->address, BUFFSIZE-1); 240 } 241 if (tmp_msginfo) { 242 procmsg_msginfo_free(&tmp_msginfo); 243 } 244 245 if (!ac_prefs->session) { 246 /* we can't reuse a previously initialised session */ 247 session = smtp_session_new(ac_prefs); 248 session->ssl_cert_auto_accept = TRUE; 249 250 smtp_session = SMTP_SESSION(session); 251 252 if (ac_prefs->set_domain && ac_prefs->domain && strlen(ac_prefs->domain)) { 253 smtp_session->hostname = g_strdup(ac_prefs->domain); 254 } else { 255 smtp_session->hostname = NULL; 256 } 257 258 port = ac_prefs->set_smtpport ? ac_prefs->smtpport : 259 ac_prefs->ssl_smtp == SSL_TUNNEL ? SSMTP_PORT : SMTP_PORT; 260 session->ssl_type = ac_prefs->ssl_smtp; 261 if (ac_prefs->ssl_smtp != SSL_NONE) 262 session->nonblocking = ac_prefs->use_nonblocking_ssl; 263 if (ac_prefs->set_gnutls_priority && ac_prefs->gnutls_priority && 264 strlen(ac_prefs->gnutls_priority)) 265 session->gnutls_priority = g_strdup(ac_prefs->gnutls_priority); 266 session->use_tls_sni = ac_prefs->use_tls_sni; 267 268 if (ac_prefs->use_smtp_auth) { 269 smtp_session->forced_auth_type = ac_prefs->smtp_auth_type; 270 if (ac_prefs->smtp_userid && strlen(ac_prefs->smtp_userid)) { 271 smtp_session->user = g_strdup(ac_prefs->smtp_userid); 272 if (password_get(smtp_session->user, 273 ac_prefs->smtp_server, "smtp", port, 274 &(smtp_session->pass))) { 275 /* NOP */; 276 } else if ((smtp_session->pass = 277 passwd_store_get_account(ac_prefs->account_id, 278 PWS_ACCOUNT_SEND)) == NULL) { 279 smtp_session->pass = 280 input_dialog_query_password_keep 281 (ac_prefs->smtp_server, 282 smtp_session->user, 283 &(ac_prefs->session_smtp_passwd)); 284 if (!smtp_session->pass) { 285 session_destroy(session); 286 return -1; 287 } 288 } 289 } else { 290 smtp_session->user = g_strdup(ac_prefs->userid); 291 if (password_get(smtp_session->user, 292 ac_prefs->smtp_server, "smtp", port, 293 &(smtp_session->pass))) { 294 /* NOP */; 295 } else if ((smtp_session->pass = passwd_store_get_account( 296 ac_prefs->account_id, PWS_ACCOUNT_RECV)) == NULL) { 297 smtp_session->pass = 298 input_dialog_query_password_keep 299 (ac_prefs->smtp_server, 300 smtp_session->user, 301 &(ac_prefs->session_smtp_passwd)); 302 if (!smtp_session->pass) { 303 session_destroy(session); 304 return -1; 305 } 306 } 307 } 308 } else { 309 smtp_session->user = NULL; 310 smtp_session->pass = NULL; 311 } 312 313 send_dialog = send_progress_dialog_create(); 314 send_dialog->session = session; 315 smtp_session->dialog = send_dialog; 316 317 progress_dialog_list_set(send_dialog->dialog, 0, NULL, 318 ac_prefs->smtp_server, 319 _("Connecting")); 320 321 if (ac_prefs->pop_before_smtp 322 && (ac_prefs->protocol == A_POP3) 323 && (time(NULL) - ac_prefs->last_pop_login_time) > (60 * ac_prefs->pop_before_smtp_timeout)) { 324 g_snprintf(buf, sizeof(buf), _("Doing POP before SMTP...")); 325 log_message(LOG_PROTOCOL, "%s\n", buf); 326 progress_dialog_set_label(send_dialog->dialog, buf); 327 progress_dialog_list_set_status(send_dialog->dialog, 0, _("POP before SMTP")); 328 GTK_EVENTS_FLUSH(); 329 inc_pop_before_smtp(ac_prefs); 330 } 331 332 g_snprintf(buf, sizeof(buf), _("Account '%s': Connecting to SMTP server: %s:%d..."), 333 ac_prefs->account_name, ac_prefs->smtp_server, port); 334 progress_dialog_set_label(send_dialog->dialog, buf); 335 log_message(LOG_PROTOCOL, "%s\n", buf); 336 337 session_set_recv_message_notify(session, send_recv_message, send_dialog); 338 session_set_send_data_progressive_notify 339 (session, send_send_data_progressive, send_dialog); 340 session_set_send_data_notify(session, send_send_data_finished, send_dialog); 341 342 } else { 343 /* everything is ready to start at MAIL FROM:, just 344 * reinit useful variables. 345 */ 346 session = SESSION(ac_prefs->session); 347 ac_prefs->session = NULL; 348 smtp_session = SMTP_SESSION(session); 349 smtp_session->state = SMTP_HELO; 350 send_dialog = (SendProgressDialog *)smtp_session->dialog; 351 was_inited = TRUE; 352 } 353 354 /* This has to be initialised for every mail sent */ 355 smtp_session->from = g_strdup(spec_from); 356 smtp_session->to_list = to_list; 357 smtp_session->cur_to = to_list; 358 smtp_session->send_data = (guchar *)get_outgoing_rfc2822_str(fp); 359 smtp_session->send_data_len = strlen((gchar *)smtp_session->send_data); 360 361 session_set_timeout(session, 362 prefs_common.io_timeout_secs * 1000); 363 /* connect if necessary */ 364 if (!was_inited && session_connect(session, ac_prefs->smtp_server, 365 port) < 0) { 366 session_destroy(session); 367 send_progress_dialog_destroy(send_dialog); 368 ac_prefs->session = NULL; 369 return -1; 370 } 371 372 debug_print("send_message_smtp(): begin event loop\n"); 373 374 if (was_inited) { 375 /* as the server is quiet, start sending ourselves */ 376 smtp_from(smtp_session); 377 } 378 379 while (session_is_running(session) && send_dialog->cancelled == FALSE 380 && SMTP_SESSION(session)->state != SMTP_MAIL_SENT_OK) 381 gtk_main_iteration(); 382 383 if (SMTP_SESSION(session)->error_val == SM_AUTHFAIL) { 384 if (ac_prefs->session_smtp_passwd) { 385 g_free(ac_prefs->session_smtp_passwd); 386 ac_prefs->session_smtp_passwd = NULL; 387 } 388 ret = -1; 389 } else if (SMTP_SESSION(session)->state == SMTP_MAIL_SENT_OK) { 390 log_message(LOG_PROTOCOL, "%s\n", _("Mail sent successfully.")); 391 ret = 0; 392 } else if (session->state == SESSION_EOF && 393 SMTP_SESSION(session)->state == SMTP_QUIT) { 394 /* consider EOF right after QUIT successful */ 395 log_warning(LOG_PROTOCOL, "%s\n", _("Connection closed by the remote host.")); 396 ret = 0; 397 } else if (session->state == SESSION_ERROR || 398 session->state == SESSION_EOF || 399 session->state == SESSION_TIMEOUT || 400 SMTP_SESSION(session)->state == SMTP_ERROR || 401 SMTP_SESSION(session)->error_val != SM_OK) 402 ret = -1; 403 else if (send_dialog->cancelled == TRUE) 404 ret = -1; 405 406 if (ret == -1) { 407 manage_window_focus_in(send_dialog->dialog->window, NULL, NULL); 408 send_put_error(session); 409 manage_window_focus_out(send_dialog->dialog->window, NULL, NULL); 410 } 411 412 /* if we should close the connection, let's do it. 413 * Close it in case of error, too, as it helps reinitializing things 414 * easier. 415 */ 416 if (!keep_session || ret != 0) { 417 if (session_is_connected(session)) 418 smtp_quit(smtp_session); 419 while (session_is_connected(session) && !send_dialog->cancelled) 420 gtk_main_iteration(); 421 session_destroy(session); 422 ac_prefs->session = NULL; 423 send_progress_dialog_destroy(send_dialog); 424 } else { 425 g_free(smtp_session->from); 426 g_free(smtp_session->send_data); 427 g_free(smtp_session->error_msg); 428 } 429 if (keep_session && ret == 0 && ac_prefs->session == NULL) 430 ac_prefs->session = SMTP_SESSION(session); 431 432 433 statusbar_pop_all(); 434 statusbar_verbosity_set(FALSE); 435 return ret; 436 } 437 438 gint send_message_smtp(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp) 439 { 440 return send_message_smtp_full(ac_prefs, to_list, fp, FALSE); 441 } 442 443 static gint send_recv_message(Session *session, const gchar *msg, gpointer data) 444 { 445 gchar buf[BUFFSIZE]; 446 SMTPSession *smtp_session = SMTP_SESSION(session); 447 SendProgressDialog *dialog = (SendProgressDialog *)data; 448 gchar *state_str = NULL; 449 450 cm_return_val_if_fail(dialog != NULL, -1); 451 452 switch (smtp_session->state) { 453 case SMTP_READY: 454 return 0; 455 case SMTP_HELO: 456 g_snprintf(buf, sizeof(buf), _("Sending HELO...")); 457 state_str = _("Authenticating"); 458 statusbar_print_all(_("Sending message...")); 459 break; 460 case SMTP_EHLO: 461 g_snprintf(buf, sizeof(buf), _("Sending EHLO...")); 462 state_str = _("Authenticating"); 463 statusbar_print_all(_("Sending message...")); 464 break; 465 case SMTP_AUTH: 466 g_snprintf(buf, sizeof(buf), _("Authenticating...")); 467 state_str = _("Authenticating"); 468 break; 469 case SMTP_FROM: 470 g_snprintf(buf, sizeof(buf), _("Sending MAIL FROM...")); 471 state_str = _("Sending"); 472 break; 473 case SMTP_RCPT: 474 g_snprintf(buf, sizeof(buf), _("Sending RCPT TO...")); 475 state_str = _("Sending"); 476 break; 477 case SMTP_DATA: 478 case SMTP_EOM: 479 g_snprintf(buf, sizeof(buf), _("Sending DATA...")); 480 state_str = _("Sending"); 481 break; 482 case SMTP_QUIT: 483 g_snprintf(buf, sizeof(buf), _("Quitting...")); 484 state_str = _("Quitting"); 485 break; 486 case SMTP_ERROR: 487 g_warning("send: error: %s", msg); 488 return 0; 489 default: 490 return 0; 491 } 492 493 progress_dialog_set_label(dialog->dialog, buf); 494 progress_dialog_list_set_status(dialog->dialog, 0, state_str); 495 496 return 0; 497 } 498 499 static gint send_send_data_progressive(Session *session, guint cur_len, 500 guint total_len, gpointer data) 501 { 502 gchar buf[BUFFSIZE]; 503 SendProgressDialog *dialog = (SendProgressDialog *)data; 504 MainWindow *mainwin = mainwindow_get_mainwindow(); 505 506 cm_return_val_if_fail(dialog != NULL, -1); 507 508 if (SMTP_SESSION(session)->state != SMTP_SEND_DATA && 509 SMTP_SESSION(session)->state != SMTP_EOM) 510 return 0; 511 512 g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"), 513 cur_len, total_len); 514 progress_dialog_set_label(dialog->dialog, buf); 515 progress_dialog_set_fraction 516 (dialog->dialog, (total_len == 0) ? 0 : (gfloat)cur_len / (gfloat)total_len); 517 518 if (mainwin) { 519 if (!gtk_widget_get_visible(mainwin->progressbar)) 520 gtk_widget_show(mainwin->progressbar); 521 gtk_progress_bar_set_fraction 522 (GTK_PROGRESS_BAR(mainwin->progressbar), 523 (total_len == 0) ? 0 : (gfloat)cur_len / (gfloat)total_len); 524 } 525 526 return 0; 527 } 528 529 static gint send_send_data_finished(Session *session, guint len, gpointer data) 530 { 531 SendProgressDialog *dialog = (SendProgressDialog *)data; 532 MainWindow *mainwin = mainwindow_get_mainwindow(); 533 534 cm_return_val_if_fail(dialog != NULL, -1); 535 536 send_send_data_progressive(session, len, len, dialog); 537 if (mainwin) { 538 gtk_widget_hide(mainwin->progressbar); 539 gtk_progress_bar_set_fraction 540 (GTK_PROGRESS_BAR(mainwin->progressbar),(gfloat)0); 541 } 542 543 return 0; 544 } 545 546 static void send_progress_dialog_size_allocate_cb(GtkWidget *widget, 547 GtkAllocation *allocation) 548 { 549 cm_return_if_fail(allocation != NULL); 550 551 gtk_window_get_size(GTK_WINDOW(widget), 552 &prefs_common.sendwin_width, &prefs_common.sendwin_height); 553 } 554 555 static SendProgressDialog *send_progress_dialog_create(void) 556 { 557 SendProgressDialog *dialog; 558 ProgressDialog *progress; 559 static GdkGeometry geometry; 560 561 dialog = g_new0(SendProgressDialog, 1); 562 563 progress = progress_dialog_create(); 564 gtk_window_set_title(GTK_WINDOW(progress->window), 565 _("Sending message")); 566 g_signal_connect(G_OBJECT(progress->showlog_btn), "clicked", 567 G_CALLBACK(send_showlog_button_cb), dialog); 568 g_signal_connect(G_OBJECT(progress->cancel_btn), "clicked", 569 G_CALLBACK(send_cancel_button_cb), dialog); 570 g_signal_connect(G_OBJECT(progress->window), "delete_event", 571 G_CALLBACK(gtk_true), NULL); 572 gtk_window_set_modal(GTK_WINDOW(progress->window), TRUE); 573 g_signal_connect(G_OBJECT(progress->window), "size_allocate", 574 G_CALLBACK(send_progress_dialog_size_allocate_cb), NULL); 575 manage_window_set_transient(GTK_WINDOW(progress->window)); 576 577 progress_dialog_get_fraction(progress); 578 579 if (!geometry.min_height) { 580 geometry.min_width = 460; 581 geometry.min_height = 250; 582 } 583 584 gtk_window_set_geometry_hints(GTK_WINDOW(progress->window), NULL, &geometry, 585 GDK_HINT_MIN_SIZE); 586 gtk_widget_set_size_request(progress->window, prefs_common.sendwin_width, 587 prefs_common.sendwin_height); 588 589 if (!prefs_common.send_dialog_invisible) { 590 gtk_widget_show_now(progress->window); 591 } 592 593 dialog->dialog = progress; 594 595 return dialog; 596 } 597 598 static void send_progress_dialog_destroy(SendProgressDialog *dialog) 599 { 600 cm_return_if_fail(dialog != NULL); 601 if (!prefs_common.send_dialog_invisible) { 602 progress_dialog_destroy(dialog->dialog); 603 } 604 g_free(dialog); 605 send_dialog = NULL; 606 } 607 608 static void send_showlog_button_cb(GtkWidget *widget, gpointer data) 609 { 610 MainWindow *mainwin = mainwindow_get_mainwindow(); 611 612 log_window_show(mainwin->logwin); 613 } 614 615 static void send_cancel_button_cb(GtkWidget *widget, gpointer data) 616 { 617 SendProgressDialog *dialog = (SendProgressDialog *)data; 618 statusbar_progress_all(0,0,0); 619 620 dialog->cancelled = TRUE; 621 } 622 623 static void send_put_error(Session *session) 624 { 625 gchar *msg; 626 gchar *log_msg = NULL; 627 gchar *err_msg = NULL; 628 629 msg = SMTP_SESSION(session)->error_msg; 630 631 switch (SMTP_SESSION(session)->error_val) { 632 case SM_ERROR: 633 case SM_UNRECOVERABLE: 634 log_msg = _("Error occurred while sending the message."); 635 if (msg) 636 err_msg = g_strdup_printf 637 (_("Error occurred while sending the message:\n%s"), 638 msg); 639 else 640 err_msg = g_strdup(log_msg); 641 break; 642 case SM_AUTHFAIL: 643 log_msg = _("Authentication failed."); 644 if (msg) 645 err_msg = g_strdup_printf 646 (_("Authentication failed:\n%s"), msg); 647 else 648 err_msg = g_strdup(log_msg); 649 break; 650 default: 651 switch (session->state) { 652 case SESSION_ERROR: 653 log_msg = 654 _("Error occurred while sending the message."); 655 err_msg = g_strdup(log_msg); 656 break; 657 case SESSION_EOF: 658 log_msg = _("Connection closed by the remote host."); 659 err_msg = g_strdup(log_msg); 660 break; 661 case SESSION_TIMEOUT: 662 log_msg = _("Session timed out. You may be able to " 663 "recover by increasing the timeout value in " 664 "Preferences/Other/Miscellaneous."); 665 err_msg = g_strdup(log_msg); 666 break; 667 default: 668 break; 669 } 670 break; 671 } 672 673 if (err_msg) { 674 log_error(LOG_PROTOCOL, "%s\n", err_msg); 675 g_free(err_msg); 676 } else { 677 if (log_msg) 678 log_warning(LOG_PROTOCOL, "%s\n", log_msg); 679 } 680 } 681