📄 mail.c
字号:
TRUE); } *(p + 1) = '\0'; snprintf(line, sizeof(line), "%s%s", key, account->password); g_free(challenge); MD5Init(&ctx); MD5Update(&ctx, line, strlen(line)); MD5Final(digest, &ctx); for (i = 0; i < 16; i++) { ascii_digest[i + i] = hex[digest[i] >> 4]; ascii_digest[i + i + 1] = hex[digest[i] & 0x0f]; } ascii_digest[i + i] = '\0'; snprintf(line, sizeof(line), "APOP %s %s\r\n", account->username, ascii_digest); server_command(&conn, mbox, line); } else if (account->authmech == AUTH_CRAM_MD5) { if (!do_cram_md5(&conn, "AUTH", mbox, NULL)) { /* SASL cancellation of authentication */ server_command(&conn, mbox, "*\r\n"); return tcp_shutdown(&conn, mbox, tcp_error_message[7], TRUE); } } else if (account->authmech == AUTH_NTLM) { if (!do_ntlm(&conn, "AUTH", mbox)) { /* SASL cancellation of authentication */ server_command(&conn, mbox, "*\r\n"); return tcp_shutdown(&conn, mbox, tcp_error_message[7], TRUE); } } else /* AUTH_USER */ { snprintf (line, sizeof (line), "USER %s\r\n", account->username); server_command(&conn, mbox, line); if (! server_response(&conn, mbox, "+OK")) return tcp_shutdown(&conn, mbox, tcp_error_message[2], TRUE); snprintf (line, sizeof (line), "PASS %s\r\n", account->password); tcp_putline(&conn, line); if (_GK.debug_level & DEBUG_MAIL) { hide_password(mbox, line, 5); format_remote_mbox_name(mbox, buf, sizeof(buf)); printf("server_command( %s ):%s", buf, line); } } if (! server_response(&conn, mbox, "+OK")) return tcp_shutdown(&conn, mbox, tcp_error_message[3], TRUE); server_command(&conn, mbox, "STAT\r\n"); if (! server_response(&conn, mbox, "+OK")) return tcp_shutdown(&conn, mbox, tcp_error_message[4], FALSE); sscanf(mbox->tcp_in->str, "+OK %d", &mbox->mail_count); snprintf (line, sizeof (line), "UIDL %d\r\n", mbox->mail_count); server_command(&conn, mbox, line); if (! server_response(&conn, mbox, "+OK")) mbox->new_mail_count = mbox->mail_count; else /* Set the new_mail_count only if the UIDL is changed to avoid | re-reporting mail is new after MUA button has been clicked. */ if ( sscanf(mbox->tcp_in->str, "+OK %*d %127s", line) == 1 && ( gkrellm_dup_string((gchar **) (&mbox->private), line) || unseen_is_new ) ) mbox->new_mail_count = mbox->mail_count; server_command(&conn, mbox, "QUIT\r\n"); tcp_close(&conn); return TRUE; }static gbooleancheck_imap(Mailbox *mbox) { MailAccount *account = mbox->account; ConnInfo conn; gint messages = 0; gint unseen = 0; gint seq = 0; gchar line[128], *ss; gchar buf[128]; if (!tcp_connect(&conn, mbox)) return FALSE; /* Is the machine we are connected to really a IMAP server? */ if (! server_response(&conn, mbox, "* OK")) return tcp_shutdown(&conn, mbox, tcp_error_message[1], FALSE);#ifdef HAVE_SSL if (account->use_ssl == SSL_STARTTLS) { snprintf(line, sizeof(line), "a%03d STARTTLS\r\n", ++seq); server_command(&conn, mbox, line); snprintf(line, sizeof(line), "a%03d OK", seq); if (!imap_completion_result(&conn, mbox, line)) return tcp_shutdown(&conn, mbox, N_("Bad response after STARTTLS."), TRUE); if (!ssl_negotiate(&conn, mbox)) return FALSE; }#endif if (account->authmech == AUTH_CRAM_MD5) { snprintf(line, sizeof(line), "a%03d AUTHENTICATE", ++seq); if (!do_cram_md5(&conn, line, mbox, NULL)) { /* SASL cancellation of authentication */ server_command(&conn, mbox, "*\r\n"); return tcp_shutdown(&conn, mbox, tcp_error_message[7], TRUE); } } else if (account->authmech == AUTH_NTLM) { snprintf(line, sizeof(line), "a%03d AUTHENTICATE", ++seq); if (!do_ntlm(&conn, line, mbox)) { /* SASL cancellation of authentication */ server_command(&conn, mbox, "*\r\n"); return tcp_shutdown(&conn, mbox, tcp_error_message[7], TRUE); } } else /* AUTH_LOGIN */ { snprintf(line, sizeof(line), "a%03d LOGIN \"%s\" \"%s\"\r\n", ++seq, account->username, account->password); tcp_putline(&conn, line); if (_GK.debug_level & DEBUG_MAIL) { line[10 + 2 + strlen(account->username)] = '\0'; hide_password(mbox, line, 11 + 2 + strlen(account->username)); format_remote_mbox_name(mbox, buf, sizeof(buf)); printf("server_command( %s ):%s", buf, line); } } snprintf(line, sizeof(line), "a%03d OK", seq); if (! imap_completion_result(&conn, mbox, line)) return tcp_shutdown(&conn, mbox, tcp_error_message[2], TRUE); /* I expect the only untagged response to STATUS will be "* STATUS ..." */ snprintf(line, sizeof(line), "a%03d STATUS \"%s\" (MESSAGES UNSEEN)\r\n", ++seq, account->imapfolder); server_command(&conn, mbox, line); if (! server_response(&conn, mbox, "*")) return tcp_shutdown(&conn, mbox, tcp_error_message[4], FALSE); if ((ss = strstr(mbox->tcp_in->str, "MESSAGES")) == NULL) { if (strrchr(mbox->tcp_in->str, '}')) { if (! server_response(&conn, mbox, "")) return tcp_shutdown(&conn, mbox, tcp_error_message[4], FALSE); if ((ss = strstr(mbox->tcp_in->str, "MESSAGES")) == NULL) return tcp_shutdown(&conn, mbox, tcp_error_message[4], FALSE); } else return tcp_shutdown(&conn, mbox, tcp_error_message[4], FALSE); } if (sscanf(ss, "MESSAGES %d", &messages) == 1) { if ((ss = strstr(mbox->tcp_in->str, "UNSEEN")) != NULL) sscanf(ss, "UNSEEN %d", &unseen); if (_GK.debug_level & DEBUG_MAIL) g_print(_("Messages: %d\nUnseen: %d\n"), messages, unseen); } mbox->mail_count = messages; mbox->new_mail_count = unseen; snprintf(line, sizeof(line), "a%03d OK", seq); imap_completion_result(&conn, mbox, line); snprintf(line, sizeof(line), "a%03d LOGOUT\r\n", ++seq); server_command(&conn, mbox, line); snprintf(line, sizeof(line), "a%03d OK", seq); imap_completion_result(&conn, mbox, line); tcp_close(&conn); return TRUE; }static gbooleanmh_sequences_new_count(Mailbox *mbox) { FILE *f; gchar buf[1024]; gchar *path, *tok; gint n0, n1; path = g_strconcat(mbox->account->path, G_DIR_SEPARATOR_S, ".mh_sequences", NULL); f = fopen(path, "r"); g_free(path); if (!f) return FALSE; have_mh_sequences = TRUE; if (mh_seq_ignore) { fclose(f); return FALSE; } while (fgets(buf, sizeof(buf), f)) { /* Look for unseen sequence like "unseen: 4 7-9 23" */ if (strncmp(buf, "unseen:", 7)) continue; tok = strtok(buf, " \t\n"); while ((tok = strtok(NULL, " \t\n")) != NULL) { if (sscanf(tok, "%d-%d", &n0, &n1) == 2) mbox->new_mail_count += n1 - n0 + 1; else mbox->new_mail_count++; } break; } fclose(f); return TRUE; } /* Sylpheed procmsg.h enums MSG_NEW as (1 << 0) and MSG_UNREAD as (1 << 1) | And procmsg_write_flags() in Sylpheeds procmsg.c writes a mail record as | a pair of ints with msgnum first followed by flags. */#define SYLPHEED_MSG_NEW 1#define SYLPHEED_MSG_UNREAD 2#define SYLPHEED_MARK_VERSION 2static gbooleansylpheed_mark_new_count(Mailbox *mbox) { FILE *f; gchar *path; gint msgnum, flags, ver, mark_files = 0; path = g_strconcat(mbox->account->path, G_DIR_SEPARATOR_S, ".sylpheed_mark", NULL); f = fopen(path, "rb"); g_free(path); if (!f) return FALSE; if ( fread(&ver, sizeof(ver), 1, f) == 1 && SYLPHEED_MARK_VERSION == ver ) { while ( fread(&msgnum, sizeof(msgnum), 1, f) == 1 && fread(&flags, sizeof(flags), 1, f) == 1 ) { if ( (flags & SYLPHEED_MSG_NEW) || ((flags & SYLPHEED_MSG_UNREAD) && unseen_is_new) ) mbox->new_mail_count += 1; ++mark_files; } if (mark_files < mbox->mail_count) mbox->new_mail_count += mbox->mail_count - mark_files; } fclose(f); return TRUE; } /* Check a mh directory for mail. The way that messages are marked as new | depends on the MUA being using. Only .mh_sequences and .sylpheed_mark | are currently checked, otherwise all mail found is considered new mail. */static gbooleancheck_mh_dir(Mailbox *mbox) { GDir *dir; gchar *name; mbox->mail_count = mbox->new_mail_count = 0; if ((dir = g_dir_open(mbox->account->path, 0, NULL)) == NULL) return FALSE; while ((name = (gchar *) g_dir_read_name(dir)) != NULL) { /* Files starting with a digit are messages. */ if (isdigit(name[0])) mbox->mail_count++; } g_dir_close(dir); /* Some MH dir clients use .mh_sequences, others such as mutt or gnus | do not. For mixed cases, it's a user option to ignore .mh_sequences. | Sylpheed uses .sylpheed_mark. */ if ( !mh_sequences_new_count(mbox) && !sylpheed_mark_new_count(mbox) ) mbox->new_mail_count = mbox->mail_count; return TRUE; } /* A maildir has new, cur, and tmp subdirectories. Any file in new | or cur that does not begin with a '.' is a mail message. It is | suggested that messages begin with the output of time() (9 digits) | but while mutt and qmail use this standard, procmail does not. | maildir(5) says: | It is a good idea for readers to skip all filenames in | new and cur starting with a dot. Other than this, | readers should not attempt to parse filenames. | So check_maildir() simply looks for files in new and cur. | But if unseen_is_new flag is set, look for ":2,*S" file suffix where | the 'S' indicates the mail is seen. | See http://cr.yp.to/proto/maildir.html */static gbooleancheck_maildir(Mailbox *mbox) { gchar path[256], *s; gchar *name; GDir *dir; mbox->new_mail_count = 0; snprintf(path, sizeof(path), "%s%cnew", mbox->account->path, G_DIR_SEPARATOR); if ((dir = g_dir_open(path, 0, NULL)) != NULL) { while ((name = (gchar *) g_dir_read_name(dir)) != NULL) mbox->new_mail_count++; g_dir_close(dir); } mbox->mail_count = mbox->new_mail_count; snprintf(path, sizeof(path), "%s%ccur", mbox->account->path, G_DIR_SEPARATOR); if ((dir = g_dir_open(path, 0, NULL)) != NULL) { while ((name = (gchar *) g_dir_read_name(dir)) != NULL) { mbox->mail_count++; if ( unseen_is_new && ( (s = strchr(name, ':')) == NULL || !strchr(s, 'S') ) ) mbox->new_mail_count++; } g_dir_close(dir); } if (_GK.debug_level & DEBUG_MAIL) g_print("check_maildir %s: total=%d old=%d new=%d\n", mbox->account->path, mbox->mail_count, mbox->old_mail_count, mbox->new_mail_count); return TRUE; } /* Count total mail and old mail in a mailbox. Old mail can be read | with a Status: R0, or can be accessed and not read with Status: O | So, new mail will be the diff - note that unread mail is not | necessarily new mail. According to stat() man page: | st_atime is changed by mknod(), utime(), read(), write(), truncate() | st_mtime is changed by mknod(), utime(), write() | But, new mail arriving (writing mailbox) sets st_mtime while reading | the mailbox (mail program reading) sets st_atime. So the test | st_atime > st_mtime is testing if mbox has been read since last new mail. | Mail readers may restore st_mtime after writting status. | And Netscape mail does status with X-Mozilla-Status: xxxS | where S is bitwise or of status flags: | 1: read 2: replied 4: marked 8: deleted | | Evolution uses status with X-Evolution: 00000000-xxxx where xxxx status is | a bitfield in hexadecimal (see enum _CamelMessageFlags in evolution/camel | source) and most importantly CAMEL_MESSAGE_SEEN = 1<<4. */ /* test if buf is a status for standard mail, mozilla or evolution */static gbooleanis_status(gchar *buf) { if (buf[0] != 'S' && buf[0] != 'X') return FALSE; if ( !strncmp(buf, "Status:", 7) /* Standard mail clients */ || !strncmp(buf, "X-Mozilla-Status:", 17) /* Netscape */ || !strncmp(buf, "X-Evolution:", 12) ) /* Mozilla */ return TRUE; else return FALSE; }static gbooleanstatus_is_old(gchar *buf) { gchar c; int tmp; /* Standard mail clients */ if ( !strncmp(buf, "Status:", 7) && (strchr(buf, 'R') || (!unseen_is_new && strchr(buf, 'O'))) ) return TRUE; /* Netscape */ if (!strncmp(buf, "X-Mozilla-Status:", 17)) { c = buf[21]; if (c < '8') /* Not deleted */ c -= '0'; if (c >= '8' || (c & 0x1)) return TRUE; } /* Evolution */ if (!strncmp(buf, "X-Evolution:", 12)) { sscanf(buf+22, "%04x", &tmp); if (tmp & (1<<4)) return TRUE; } return FALSE; } /* test if a mail is marked as deleted | Evolution uses status with X-Evolution: 00000000-xxxx where xxxx status is | a bitfield in hexadecimal (see enum _CamelMessageFlags in evolution/camel source) | and most importantly CAMEL_MESSAGE_DELETED = 1<<1. */static gbooleanstatus_is_deleted(gchar *buf) { gint tmp; /* Standard mail clients if ( !strncmp(buf, "Status:", 7) ) */ /* Netscape if (!strncmp(buf, "X-Mozilla-Status:", 17)) */ /* Evolution */ if (!strncmp(buf, "X-Evolution:", 12)) { sscanf(buf+22, "%04x", &tmp); if (tmp & (1<<1)) return TRUE; /* Junk is not explicitly marked as deleted but is shown as if | where in evolution */ if (tmp & (1<<7)) return TRUE; } return FALSE; }static gbooleancheck_mbox(Mailbox *mbox) { FILE *f; struct utimbuf ut; struct stat s; gchar buf[1024]; gchar mpart_sep[1024]; gint in_header = FALSE; gint marked_read = FALSE; gint is_multipart = FALSE; if (stat(mbox->account->path, &s) != 0) { mbox->mail_count = mbox->old_mail_count = mbox->new_mail_count = 0; mbox->last_mtime = 0; mbox->last_size = 0; if (_GK.debug_level & DEBUG_MAIL) printf("check_mbox can't stat(%s): %s\n", mbox->account->path, g_strerror(errno)); return FALSE; } /* Message no-counting mode reports new mail based on mailbox | modified time and size. */ if (count_mode == MSG_NO_COUNT) { if ( s.st_size > 0 && s.st_size >= mbox->last_size && s.st_mtime >= s.st_atime ) mbox->new_mail_count = TRUE; else mbox->new_mail_count = FALSE; mbox->mail_count = (s.st_size > 0) ? 1 : 0; /* boolean, not used */ mbox->old_mail_count = 0; /* not used */ mbox->last_size = s.st_size; mbox->last_mtime = s.st_mtime; return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -