📄 mail.c
字号:
/* GKrellM| Copyright (C) 1999-2006 Bill Wilson|| Author: Bill Wilson billw@gkrellm.net| Latest versions might be found at: http://gkrellm.net|| This program is free software which I release under the GNU General Public| License. You may redistribute and/or modify this program under the terms| of that license as published by the Free Software Foundation; either| version 2 of the License, or (at your option) any later version.|| This program is distributed in the hope that it will be useful,| but WITHOUT ANY WARRANTY; without even the implied warranty of| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the| GNU General Public License for more details. Version 2 is in the| COPYRIGHT file in the top level directory of this distribution.| | To get a copy of the GNU General Puplic License, write to the Free Software| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "gkrellm.h"#include "gkrellm-private.h"#ifdef WIN32#include <winsock2.h>#else#include <utime.h>#include <sys/time.h>#endif#include <errno.h>#include "pixmaps/mail/decal_mail.xpm"#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)#define HAVE_MD5_H#endif#if defined(HAVE_GNUTLS)#include <gnutls/openssl.h>#include <pthread.h>#define MD5Init MD5_Init#define MD5Update MD5_Update#define MD5Final MD5_FinalGCRY_THREAD_OPTION_PTHREAD_IMPL;#else#if defined(HAVE_SSL)#include <openssl/ssl.h>#include <openssl/md5.h>#define MD5Init MD5_Init#define MD5Update MD5_Update#define MD5Final MD5_Final#else#if defined(HAVE_MD5_H)#include <md5.h>#else#include "md5.h"#endif#endif#endif#include "ntlm.h"#define MUTE_FLAG -1/* msg_count_mode has 3 states*/#define MSG_NEW_TOTAL_COUNT 0#define MSG_NEW_COUNT 1#define MSG_NO_COUNT 2/* animation_mode states*/#define ANIMATION_NONE 0#define ANIMATION_ENVELOPE 1#define ANIMATION_PENGUIN 2#define ANIMATION_BOTH 3/* # of seconds to wait for a response from a POP3 or IMAP server*/#define TCP_TIMEOUT 30#define DEFAULT_POP3_PORT "110"#define DEFAULT_IMAP_PORT "143"#define DEFAULT_IMAPS_PORT "993"#define DEFAULT_POP3S_PORT "995" /* A mailbox type has bits encoding how to check the mailbox (inline code | check or threaded check). | Threaded checks and the fetch program are remote checks */#define MBOX_CHECK_FETCH 0x1000#define MBOX_CHECK_INLINE 0x2000#define MBOX_CHECK_THREADED 0x4000#define MBOX_CHECK_TYPE_MASK 0xf000 /* Counts for mailboxes created and checked in other plugins can be shown */#define MBOX_EXTERNAL 0x10 /* Mailboxes internally checked and created via the Mail->Mailboxes config */#define MBOX_INTERNAL 0x20 /* Here's the list of all the mailbox types the Mail monitor knows about. | The MBOX_FETCH is a pseudo internal mailbox where the counts read from | the fetch program are kept. Additionally MBOX_FETCH_TOOLTIP types | are constructed just so the fetch programs output lines can be | reported in a tooltip. Real mailboxes that GKrellM creates in its | config and knows how to check have MBOX_INTERNAL set. And | finally there can be external (plugin) mailboxes created which | can have their check function called at the update intervals. If the | plugin reports back the count results, the animation/sound can be | triggered for the plugin. (Don't know if EXTERNAL guys will ever be used) | Internal mailboxes can be remote or local. Remote mailboxes have an | authorization protocol that subdivides them into types. Local mailboxes | currently have separate mboxtype values but I may later group them | into a MBOX_LOCAL type with a subdivision protocol like is currently | done for remote mailboxes. */#define MBOX_FETCH (MBOX_CHECK_FETCH)#define MBOX_MBOX (MBOX_CHECK_INLINE | MBOX_INTERNAL | 0)#define MBOX_MAILDIR (MBOX_CHECK_INLINE | MBOX_INTERNAL | 1)#define MBOX_MH_DIR (MBOX_CHECK_INLINE | MBOX_INTERNAL | 2)#define MBOX_REMOTE (MBOX_CHECK_THREADED | MBOX_INTERNAL | 3)#define MBOX_FETCH_TOOLTIP (6)#define MBOX_LOCAL_PLUGIN (MBOX_CHECK_INLINE | MBOX_EXTERNAL)#define MBOX_REMOTE_PLUGIN (MBOX_CHECK_THREADED | MBOX_EXTERNAL)#define PROTO_POP3 0#define PROTO_IMAP 1#define AUTH_PLAINTEXT 0#define AUTH_USER AUTH_PLAINTEXT /* POP3 only */#define AUTH_APOP 1 /* POP3 only */#define AUTH_LOGIN AUTH_PLAINTEXT /* IMAP4 only */#define AUTH_CRAM_MD5 2#define AUTH_NTLM 3#define SSL_NONE 0#define SSL_TRANSPORT 1#define SSL_STARTTLS 2 /* Authorization protocol strings to write into the config for remote | mailboxes. */typedef struct { gchar *string; gint protocol; gint authmech; } AuthType;static AuthType auth_strings[] = { { "POP3", PROTO_POP3, AUTH_USER }, { "POP3_(APOP)", PROTO_POP3, AUTH_APOP }, { "POP3_(CRAM-MD5)", PROTO_POP3, AUTH_CRAM_MD5 }, { "POP3_(NTLM)", PROTO_POP3, AUTH_NTLM }, { "IMAP", PROTO_IMAP, AUTH_LOGIN }, { "IMAP_(CRAM-MD5)", PROTO_IMAP, AUTH_CRAM_MD5 }, { "IMAP_(NTLM)", PROTO_IMAP, AUTH_NTLM }, { NULL, -1, -1 } }; /* Save local mailbox type strings in the config in case I later change | to an option_menu selection for subdividing a MBOX_LOCAL type. | Currently local mailbox types are determined in get_local_mboxtype(). */static gchar *mbox_strings[3] = { "mbox", "Maildir", "MH_mail" };static GkrellmMonitor *mon_mail;typedef struct { gchar *path, *homedir_path; gchar *server; gchar *username; gchar *password; gchar *imapfolder; gint mboxtype; gint protocol; gint authmech; gint port; gint use_ssl; /* Always SSL_NONE if !HAVE_SSL */ } MailAccount;typedef struct { MailAccount *account; gboolean busy; GString *tcp_in; gboolean (*check_func)(); gpointer data; /* For external mailboxes (in plugins) */ GThread* thread; gint mail_count; gint new_mail_count; gint old_mail_count; gint prev_mail_count, prev_new_mail_count; time_t last_mtime; off_t last_size; gboolean is_internal; /* Internal mail message (ie: localmachine) */ gboolean need_animation, prev_need_animation; gchar *warn_msg; gboolean warned; void *private; } Mailbox;static GList *mailbox_list;typedef struct { gchar *command; GString *read_gstring; /* Bytes read from pipe stored here */ gint pipe; } Mailproc;typedef struct { gint fd;#ifdef HAVE_SSL SSL *ssl; SSL_CTX *ssl_ctx;#endif } ConnInfo;Mailbox *mail_fetch; /* Internal mailbox: fetch command */static Mailproc mail_user_agent;static gchar *mail_notify; /* Sound */static GkrellmPiximage *decal_mail_piximage;static gint run_animation, decal_frame;static gint remote_check_timeout = 5; /* Minutes */static gint local_check_timeout = 4; /* Seconds */static gboolean fetch_check_is_local;static GkrellmPanel *mail;static GtkTooltips *tooltip;static GkrellmDecalbutton *mua_button;static gboolean enable_mail, mute_mode, super_mute_mode, cont_animation_mode, mua_inhibit_mode, /* Inhibit checking if MUA launched */ enable_multimua, /* allow multiple MUA instances */ count_mode, fetch_check_only_mode, reset_remote_mode, unseen_is_new, /* Accessed but unread */ local_supported = TRUE;static gboolean mh_seq_ignore, have_mh_sequences, checking_mh_mail;static gint animation_mode = ANIMATION_BOTH;static gboolean force_mail_check;static gint new_mail_count, total_mail_count;static gint check_timeout;static gint show_tooltip = FALSE;static gint anim_frame, anim_dir, anim_pause;static gint style_id; /* This may be called from gkrellm_sys_main_init() */voidgkrellm_mail_local_unsupported(void) { local_supported = FALSE; }GThread *gkrellm_mail_get_active_thread(void) { GList *list; Mailbox *mbox; GThread *thread; for (list = mailbox_list; list; list = list->next) { mbox = (Mailbox *) list->data; thread = mbox->thread; if (thread) return thread; } return NULL; }static voidfree_account(MailAccount *account) { if (!account) return; g_free(account->path); g_free(account->homedir_path); g_free(account->server); g_free(account->username); g_free(account->password); g_free(account->imapfolder); g_free(account); }static voidfree_mailbox(Mailbox *mbox) { /* If user changes mailbox config list while a mailbox thread is busy, | freeing the mbox can cause a segfault. Rare, so allow the leak. */ if (mbox->busy) return; free_account(mbox->account); g_free(mbox->warn_msg); g_free(mbox); }static gbooleanformat_remote_mbox_name(Mailbox *mbox, gchar *buf, size_t len) { MailAccount *account = mbox->account; if (account->imapfolder && *account->imapfolder) snprintf(buf, len, "%s-%s@%s", account->username, account->imapfolder, account->server); else if (account->server) snprintf(buf, len, "%s@%s", account->username, account->server); else if (account->username) snprintf(buf, len, "%s", account->username); else { snprintf(buf, len, "??"); return FALSE; } return TRUE; } /* Make tooltip visible/invisible and fill it with mailbox names | containing new mail. */static voidupdate_tooltip(void) { GList *list; Mailbox *mbox; MailAccount *account; GString *mboxes = NULL; gchar buf[128]; if (show_tooltip) { mboxes = g_string_sized_new(512); for (list = mailbox_list; list; list = list->next) { mbox = (Mailbox *) list->data; account = mbox->account; if (mbox->new_mail_count > 0) { if (( account->mboxtype == MBOX_MBOX || account->mboxtype == MBOX_MAILDIR || account->mboxtype == MBOX_MH_DIR || account->mboxtype == MBOX_LOCAL_PLUGIN || account->mboxtype == MBOX_REMOTE_PLUGIN ) && account->path ) snprintf(buf, sizeof(buf), "%s", account->homedir_path ? account->homedir_path : account->path); else if (! format_remote_mbox_name(mbox, buf, sizeof(buf))) continue; /* Can't get a name, so no tooltip for you! */ if (mboxes->len > 0) g_string_append_c(mboxes, '\n'); g_string_append(mboxes, buf); if (count_mode == MSG_NEW_TOTAL_COUNT) snprintf(buf, sizeof(buf), "(%d/%d)", mbox->new_mail_count, mbox->mail_count); else snprintf(buf, sizeof(buf), "(%d)", mbox->new_mail_count); g_string_append(mboxes, buf); } } } if (show_tooltip && mboxes && mboxes->len > 0) { gtk_tooltips_set_tip(tooltip, mail->drawing_area, mboxes->str, ""); gtk_tooltips_enable(tooltip); } else gtk_tooltips_disable(tooltip); if (mboxes) g_string_free(mboxes, TRUE); } /* Look at a From line to see if it is valid, lines look like: | From sending_address dayofweek month dayofmonth timeofday year | eg: From billw@gkrellm.net Fri Oct 22 13:52:49 2010 */static gintis_From_line(Mailbox *mbox, gchar *buf) { gchar sender[512]; gint dayofmonth = 0; if (strncmp(buf, "From ", 5)) return FALSE; /* In case sending address missing, look for a day of month | number in field 3 or 4 (0 based). */ sender[0] = '\0'; if (sscanf(buf, "%*s %*s %*s %d", &dayofmonth) != 1) { if (sscanf(buf, "%*s %511s %*s %*s %d", sender, &dayofmonth) != 2) return FALSE; } if (dayofmonth < 1 || dayofmonth > 31) return FALSE; if (strcmp(sender, "MAILER-DAEMON") == 0) mbox->is_internal = TRUE; return TRUE; } /* Check if this is a Content-Type-line. If it contains a boundary | field, copy boundary string to buffer (including two leading and | trailing dashes marking the end of a multipart mail) and return | true. Otherwise, return false. */static gintis_multipart_mail(gchar *buf, gchar *separator) { gchar *fieldstart; gchar *sepstart; gint seplen; if (strncmp(buf, "Content-Type: ", 14) != 0) return FALSE; if (strncmp(&buf[14], "multipart/", 10) != 0) return FALSE; fieldstart = &buf[14]; while (*fieldstart!=0) { while (*fieldstart!=0 && *fieldstart!=';') fieldstart++; if (*fieldstart==';') fieldstart++; while (*fieldstart!=0 && *fieldstart==' ') fieldstart++; if (strncmp(fieldstart, "boundary=", 9) == 0) { sepstart = fieldstart + 9; if (sepstart[0]=='"') { sepstart++; seplen = 0; while (sepstart[seplen]!='"' && sepstart[seplen]>=32) seplen++; } else { seplen = 0; while (sepstart[seplen]!=';' && sepstart[seplen]>32) seplen++; } strcpy(separator,"--"); strncpy(&separator[2],sepstart,seplen); strcpy(&separator[seplen+2],"--"); return TRUE; } } return FALSE; } /* Hide a password that is embedded in a string. */static voidhide_password(Mailbox *mbox, gchar *line, gint offset) { gint n; n = strlen(mbox->account->password); while (n--) line[offset + n] = '*'; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -