📄 mail.c
字号:
} /* If the mailboxes have been modified since last check, count | the new/total messages. */ if ( s.st_mtime != mbox->last_mtime || s.st_size != mbox->last_size || force_mail_check ) { if ((f = fopen(mbox->account->path, "r")) == NULL) { if (_GK.debug_level & DEBUG_MAIL) printf("check_mbox can't fopen(%s): %s\n", mbox->account->path, g_strerror(errno)); return FALSE; } mbox->mail_count = 0; mbox->old_mail_count = 0; while(fgets(buf, sizeof(buf), f)) { if (is_multipart && !in_header) { /* Skip to last line of multipart mail */ if (strncmp(buf,mpart_sep,strlen(mpart_sep))==0) is_multipart = FALSE; } else if (buf[0] == '\n') { in_header = FALSE; mbox->is_internal = FALSE; } else if (is_From_line(mbox, buf)) { mbox->mail_count += 1; in_header = TRUE; marked_read = FALSE; } else if (in_header && is_status(buf)) { if (status_is_old(buf) && !marked_read) { mbox->old_mail_count += 1; marked_read = TRUE; } if (status_is_deleted(buf)) { if (marked_read) mbox->old_mail_count -= 1; mbox->mail_count -= 1; } } else if (in_header && mbox->is_internal) { if (strncmp(buf, "From: Mail System Internal Data", 31) == 0) { in_header = FALSE; mbox->mail_count -= 1; mbox->is_internal = FALSE; } } else if (in_header && is_multipart_mail(buf,mpart_sep)) { is_multipart = TRUE; } } fclose(f); /* Restore the mbox stat times for other mail checking programs and | so the (st_atime > st_mtime) animation override below will work. */ ut.actime = s.st_atime; ut.modtime = s.st_mtime; utime(mbox->account->path, &ut); mbox->last_mtime = s.st_mtime; mbox->last_size = s.st_size; if (_GK.debug_level & DEBUG_MAIL) g_print("check_mbox %s: total=%d old=%d\n", mbox->account->path, mbox->mail_count, mbox->old_mail_count); } /* Set the animation state when new mail count changes, and override | the animation to false if mbox has been accessed since last modify | (A MUA has probably read the mbox). */ mbox->new_mail_count = mbox->mail_count - mbox->old_mail_count; if (s.st_atime > s.st_mtime) { mbox->need_animation = FALSE; mbox->prev_new_mail_count = mbox->new_mail_count; } return TRUE; }static GkrellmDecal *mail_text_decal;static GkrellmDecal *mail_icon_decal;static voiddraw_mail_text_decal(gint new_mail_count, gint mail_count) { GkrellmTextstyle ts, ts_save; gint x, w; GkrellmPanel *p; GkrellmDecal *d; GkrellmStyle *style; GkrellmMargin *m; gchar buf[32], nbuf[16], tbuf[16]; p = mail; d = mail_text_decal; ts_save = d->text_style; if (new_mail_count == MUTE_FLAG) { snprintf(buf, sizeof(buf), _("mute")); ts = *gkrellm_meter_alt_textstyle(style_id); /* Use the alt color */ ts.font = d->text_style.font; } else { ts = d->text_style; if (count_mode == MSG_NO_COUNT) buf[0] = '\0'; else if (count_mode == MSG_NEW_COUNT) { if (new_mail_count == 0) strcpy(buf, "-"); else snprintf(buf, sizeof(buf), "%d", new_mail_count); } else /* MSG_NEW_TOTAL_COUNT */ { if (new_mail_count == 0) strcpy(nbuf, "-"); else snprintf(nbuf, sizeof(nbuf), "%d", new_mail_count); if (mail_count == 0) strcpy(tbuf, "-"); else snprintf(tbuf, sizeof(tbuf), "%d", mail_count); snprintf(buf, sizeof(buf), "%s/%s", nbuf, tbuf); } } w = gkrellm_gdk_string_width(ts.font, buf); if (w > d->w) { ts.font = gkrellm_meter_alt_textstyle(style_id)->font; w = gkrellm_gdk_string_width(ts.font, buf); } style = gkrellm_meter_style(style_id); m = gkrellm_get_style_margins(style); x = gkrellm_chart_width() * p->label->position / GKRELLM_LABEL_MAX; x -= m->right + w / 2; if (p->label->position >= 50) x -= mail_icon_decal->w; if (x > d->w - w) x = d->w - w; if (x < 0) x = 0; d->text_style = ts; d->x_off = x; gkrellm_draw_decal_text(p, d, buf, 0); d->text_style = ts_save; }static voidmbox_set_animation_state(Mailbox *mbox) { if (mbox->new_mail_count != mbox->prev_new_mail_count) mbox->need_animation = (mbox->new_mail_count > mbox->prev_new_mail_count); }static voidupdate_krell_animation_frame(void) { /* Run the animation. Just go back and forth with a pause on | frames 1 and full_scale - 1 (frames 0 and full_scale are cut off). | Frame 0 is blank anyway, and frame full_scale is just not used. */ if (anim_pause-- <= 0) { if (anim_frame <= 1) anim_dir = 1; if (anim_frame >= KRELL(mail)->full_scale - 1) anim_dir = -1; anim_frame += anim_dir; anim_frame %= KRELL(mail)->full_scale; if (anim_frame == 1 || anim_frame == KRELL(mail)->full_scale - 1) anim_pause = 4; } } /* I popen the mail_user_agent so I can know if it is running and | the mail_fetch so I can process fetchmail/flist/fetcho/... output. | Reading the pipes need to not block so GKrellM won't freeze. | So, I need a special non-blocking pipe line reading routine. */static voidpipe_command(Mailproc *mp) { gchar **argv; GError *err = NULL; gboolean res; if (mp->pipe >= 0) /* Still running? */ { if (_GK.debug_level & DEBUG_MAIL) g_print("mail pipe_command: <%s> still running.\n", mp->command); return; } if (!mp->command || *mp->command == '\0') return; g_shell_parse_argv(mp->command, NULL, &argv, NULL); if (_GK.debug_level & DEBUG_MAIL) g_print("mail pipe_command <%s>\n", mp->command); mp->pipe = -1; res = g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, &mp->pipe, NULL, &err); if (!res && err) { gkrellm_message_dialog(NULL, err->message); g_error_free(err); } if (mp->read_gstring) mp->read_gstring = g_string_truncate(mp->read_gstring, 0); else mp->read_gstring = g_string_new(""); fcntl(mp->pipe, F_SETFL, O_NONBLOCK); g_strfreev(argv); } /* Accumulate non-blocking reads from a pipe into a gstring. Then | try to read a single line from the gstring. If a line is read, | return the count of chars in the line. But if no line can be read | and the other end of the pipe has exited (pipe eof), return -1. | Otherwise return 0 to indicate no line is available but the pipe | producer is still alive. | Why this trouble?: the stdio fgets() reading from a non-blocking | stream is not guaranteed to return complete '\n' delimited lines. */static gintfgets_pipe(gchar *line, gint len, Mailproc *mp) { gchar buf[512]; gint n; if (mp->pipe >= 0) { n = read(mp->pipe, buf, sizeof(buf) - 1); if (n <= 0) { if (errno != EINTR && errno != EAGAIN) { if (close(mp->pipe) < 0 && errno == EINTR) close(mp->pipe); mp->pipe = -1; } } else { buf[n] = '\0'; mp->read_gstring = g_string_append(mp->read_gstring, buf); } } if (gkrellm_getline_from_gstring(&mp->read_gstring, line, len)) return strlen(line); if (mp->pipe < 0) { if (mp->read_gstring) g_string_free(mp->read_gstring, TRUE); mp->read_gstring = NULL; return -1; } return 0; }static gbooleanmua_is_launched(void) { gchar buf[128]; gint n; if (mail_user_agent.pipe == -1) return FALSE; while ((n = fgets_pipe(buf, sizeof(buf), &mail_user_agent)) > 0) ; return (n < 0) ? FALSE : TRUE; } /* Read mail_fetch pipe and if fetch_check_only_mode, look for output | of fetchmail -c or flist so I can report mail from these programs. | | eg. for MH mail, the nmh program flist -all (from the man page): | /work/Mail has 5 in sequence unseen (private); out of 46 | inbox+ has 10 in sequence unseen ; out of 153 | junklist has 0 in sequence unseen ; out of 63 | | For fetchmail, if no remote mail, I get: | fetchmail: No mail for billw at mail.wt.net | If remote mail i will get lines like: | 1 message for billw at mail.wt.net (32743 octets). | or, as reported by a user, there could be: | 26 messages (25 seen) for billw at mail.wt.net | If the remote mail is fetched, I get additional lines like: | reading message 1 of 1 (32743 octets) .................... flushed | Note: above 26 messages (25 seen) should show as 1/26 on panel. | | And fetchmail can't make up its mind. A user gets this with 5.2.0: | fetchmail: 5.2.0 querying xx.yy.net (protocol POP3) at Thu, 20 Jan 2000... | fetchmail: 2 messages for uuu at xx.yy.net (20509 octets). */ /* Since there is now internal POP3 and IMAP checking, this will not be | used as much, but there is still flist, using fetchmail for ssl, etc. | Anyway, here's the code to grok the above mess! */static gbooleanparse_fetch_line(gchar *line, gint *msg, gint *seen) { gchar *s, *p, *buf; gint n, n1, n2; gint tok_count = 0; gint state = 0, seen_flag = FALSE, unseen_flag = FALSE; *msg = 0; *seen = 0; n1 = n2 = 0; buf = g_strdup(line); s = strtok(buf, " \t()\n"); /* Trap out badly set Fetch/check option. */ if (!s || !strcmp(s, "reading") || !strcmp(s, "skipping")) { g_free(buf); return FALSE; } if (_GK.debug_level & DEBUG_MAIL) printf(" parse["); while (s) { if (++tok_count > 3 && state == 0) /* need a int within 3 tokens */ break; n = strtol(s, &p, 0); if (*p == ' ' || *p == '\t' || *p == '\0' || *p == '\n') { /* Have an integer, and not a x.y version number */ if (_GK.debug_level & DEBUG_MAIL) printf("*<%s>,st=%d,", s, state); if (state == 0) n1 = n; else if (state == 1) n2 = n; if (_GK.debug_level & DEBUG_MAIL) printf("n1=%d,n2=%d state=%d*", n1, n2, state); ++state; } else if (!strcmp(s, "seen") || !strcmp(s, _("seen"))) seen_flag = TRUE; else if (!strcmp(s, "unseen")) unseen_flag = TRUE; s = strtok(NULL, " \t()\n"); } if (state > 1 && seen_flag) /* 26 messages (25 seen) ... */ { *msg = n1; *seen = n2; } else if (state > 1 && unseen_flag) /* /xxx has 5 in sequence unseen ... */ { *msg = n2; *seen = n2 - n1; } else if (state > 0) /* 1 message for billw at ... */ *msg = n1; /* or Fetchmail: 1 message for .... */ if (_GK.debug_level & DEBUG_MAIL) printf("]snf=%d sunf=%d msg=%d seen=%d STATE=%d\n", seen_flag, unseen_flag, *msg, *seen, state); g_free(buf); return TRUE; }static gintcompare_mailboxes(gconstpointer a, gconstpointer b) { gchar a_name[128]; gchar b_name[128]; format_remote_mbox_name((Mailbox *)a, a_name, sizeof(a_name)); format_remote_mbox_name((Mailbox *)b, b_name, sizeof(b_name)); return strcmp(a_name, b_name); }static voidmake_fetch_tooltip(gchar *line, gint msg, gint seen) { Mailbox *mbox; MailAccount *account; GList *old_mbox_pointer; gchar buf[64], *s; mbox = g_new0(Mailbox, 1); account = g_new0(MailAccount, 1); mbox->account = account; account->mboxtype = MBOX_FETCH_TOOLTIP; if ((s = strstr(line, "sequence unseen")) != NULL) /* flist */ { sscanf(line, "%63s", buf); account->username = g_strdup(buf); } else if ((s = strstr(line, " for ")) != NULL) /* fetchmail */ { sscanf(s + 5, "%63s", buf); account->username = g_strdup(buf); if ((s = strstr(line, " at ")) != NULL) { sscanf(s + 4, "%63s", buf); account->server = g_strdup(buf); } if ((s = strstr(line, "(folder ")) != NULL) { sscanf(s + 8, "%63[^)]", buf); account->imapfolder = g_strdup(buf); } } else { free_mailbox(mbox); return; } old_mbox_pointer = g_list_find_custom(mailbox_list, mbox, (GCompareFunc) compare_mailboxes); if (old_mbox_pointer) { free_mailbox(mbox); mbox = (Mailbox *) old_mbox_pointer->data; if (mbox->account->mboxtype == MBOX_FETCH_TOOLTIP) { mbox->mail_count = msg; mbox->new_mail_count = msg - seen; } } else { mbox->mail_count = msg; mbox->new_mail_count = msg - seen; mailbox_list = g_list_insert_sorted(mailbox_list, mbox, (GCompareFunc)(compare_mailboxes)); } } /* Read output lines from the fetch/check program. If fetch_check_only_mode | is set, parse the lines to try to read message counts so they can be | reported ("fetchmail -c" or equiv should be configured). However, if | the mode is not set, then just read lines and waste them because mail | is presumably being downloaded into local mailboxes. */static voidread_mail_fetch(void) { Mailproc *mp = (Mailproc *) mail_fetch->private; gchar buf[128]; gint n, msg, seen; while ((n = fgets_pipe(buf, sizeof(buf), mp)) > 0) /* non-blocking */ { if (_GK.debug_level & DEBUG_MAIL) printf("read_mail_fetch(%d): %s\n", fetch_check_only_mode, buf); if (fetch_check_only_mode) { if (parse_fetch_line(buf, &msg, &seen)) make_fetch_tooltip(buf, msg, seen); if (msg > 0) { mail_fetch->mail_count += msg; mail_fetch->old_mail_count += seen; } } } /* When fetch program is done, flag not busy so new counts will be used. */ if (n < 0) { if (fetch_check_only_mode) { mail_fetch->new_mail_count = mail_fetch->mail_count - mail_fetch->old_mail_count; mbox_set_animation_state(mail_fetch); } mail_fetch->busy = FALSE; } }static voidreset_mail_fetch(void) { Mailproc *mp = (Mailproc *) mail_fetch->private;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -