x-face patch for Mutt 1.5.6 Copied from Debian's slrnface package: http://dave.willfork.com/slrnface/ Upstream Author: Drazen Kacar Copyright: /usr/share/common-licenses/GPL --- mutt-1.4./README.xface Thu Jan 1 01:00:00 1970 +++ mutt-1.4/README.xface Sat Aug 24 02:29:23 2002 @@ -0,0 +1,80 @@ +This is slrnface, a small helper utility which displays X-Faces on behalf +of programs like slrn and mutt when they are run in the X11 terminal +emulator. + +Requirements: + +a) X11. +b) Terminal emulator which sets WINDOWID environment variable. Most of the + ones in common use will set it. If you're using some terminal emulator + which doesn't have this capability, you'll have to set it yourself. + +How to build: + +a) Install libcompface. I recommend getting the source from the nearest + Debian GNU/Linux mirror because there's a patch which adds the + ability to output XBM image, as well as the historic brain dead + format. Slrnface doesn't use that feature, but it might be handy for + something else. + +b) Edit Makefile. + +c) Invoke make. + +d) Install with "make install". + +Upgrading from version 1.x: + + If you have used one of the older versions of slrnface, you probably + have .slrnface file in your home directory. You can delete it, because + the new version doesn't use it any more. Instead, the pipes will be + created in $HOME/.slrnfaces directory. There are no other user visible + changes. + +Using slrnface with slrn: + + This version requires S-Lang 1.4 or later and slrn 0.9.7.4. It might + work with slrn 0.9.7.3, but I haven't tested that configuration. It + will not work properly with older versions. + + In case you can't or won't upgrade, take a look at the slrnface home + page. You'll find older versions which might work with what you have. + + Take a look at slrnface.sl, edit if you want and then include it in + your .slrnrc, like this: + + interpret slrnface.sl + + Run slrn. + +Using slrnface with mutt: + + Mutt doesn't have a way to use some kind of embeded interpreter, like + S-Lang. Since Mutt's current capabilities are not good enough for our + purposes, a patch for the source is provided. It has been tested with + mutt 1.4, but it should work with the 1.3.x series, if x is high + enough. + + Uncompress mutt 1.4 source and apply mutt.patch from the slrnface + distribution. + + Compile mutt as usual. + + Edit your ~/.muttrc and add: + + set xface=yes + + Run mutt. + +If you think X-Faces are not placed at the appropriate location on your +terminal emulator window or you don't like the colors, set some X resources. +Read the man page for more information. Additional documentation is in the +doc directory. + +Licence: GPL. See file called COPYING. + +Special thanks to Mark R. Bowyer for proofreading the man page. + +Home page: http://dave.willfork.com/slrnface/ + +dave@willfork.com diff -urp ../MUTT/mutt/PATCHES mutt/PATCHES --- ../MUTT/mutt/PATCHES 2002-12-09 18:44:54.000000000 +0100 +++ mutt/PATCHES 2004-07-21 16:02:16.000000000 +0200 @@ -0,0 +1 @@ +patch-1.5.6.cb.xface.1 diff -urp ../MUTT/mutt/globals.h mutt/globals.h --- ../MUTT/mutt/globals.h.orig 2007-03-26 14:49:03.226880430 +0200 +++ mutt/globals.h 2007-03-26 14:51:13.227945753 +0200 @@ -218,6 +218,8 @@ WHERE ALIAS *Aliases INITVAL (0); WHERE LIST *UserHeader INITVAL (0); +WHERE int slrnface_fd INITVAL (-1); + /*-- formerly in pgp.h --*/ WHERE REGEXP PgpGoodSign; WHERE char *PgpSignAs; diff -urp ../MUTT/mutt/init.c mutt/init.c --- ../MUTT/mutt/init.c 2004-07-18 01:25:28.000000000 +0200 +++ mutt/init.c 2004-07-21 13:33:47.000000000 +0200 @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include void toggle_quadoption (int opt) @@ -2356,3 +2358,131 @@ int mutt_get_hook_type (const char *name return c->data; return 0; } + +void mutt_start_slrnface(void) +{ + char *fifo; + int pathlen, status; + pid_t pid, pidst; + struct utsname u; + + if (!option(OPTXFACE)) + return; + + /* + * If we don't have display, there's no point. The user probably knows, + * so fail silently. + */ + if (!getenv("DISPLAY")) + return; + /* If there is no WINDOWID, complain. */ + if (!getenv ("WINDOWID")) + { + mutt_error (_("Cannot run slrnface: WINDOWID not found in environment.")); + return; + } + + uname (&u); + pathlen = strlen (Homedir) + sizeof("/.slrnfaces/") + + strlen (u.nodename) + 30; + fifo = safe_malloc (pathlen); + sprintf (fifo, "%s/.slrnfaces", Homedir); + if (mkdir (fifo, 0700)) + { + if (errno != EEXIST) + { + mutt_error (_("Cannot run slrnface: failed to create %s: %s."), + fifo, strerror(errno)); + return; + } + } + else + { + FILE *fp; + + /* We'll abuse fifo filename memory here. It's long enough. */ + sprintf (fifo, "%s/.slrnfaces/README", Homedir); + if ((fp = fopen (fifo, "w")) != NULL) + { + fputs (_( +"This directory is used to create named pipes for communication between\n" +"slrnface and its parent process. It should normally be empty because\n" +"the pipe is deleted right after it has been opened by both processes.\n\n" +"File names generated by slrnface have the form \"hostname.pid\". It is\n" +"probably an error if they linger here longer than a fraction of a second.\n\n" +"However, if the directory is mounted from an NFS server, you might see\n" +"special files created by your NFS server while slrnface is running.\n" +"Do not try to remove them.\n"), fp); + fclose (fp); + } + } + + status = snprintf (fifo, pathlen, "%s/.slrnfaces/%s.%ld", Homedir, + u.nodename, (long)getpid()); + if (status < 0) + goto clean_face; + + unlink (fifo); + if (mkfifo (fifo, 0600) < 0) + { + mutt_error (_("Cannot run slrnface, failed to create %s: %s."), fifo, + strerror(errno)); + goto clean_face; + } + + pid = fork(); + switch (pid) + { + case -1: break; + case 0: execlp ("slrnface", "slrnface", fifo, (char *)0); + /* This is child, exit on error. */ + _exit (10); + default: do { + pidst = waitpid (pid, &status, 0); + } while (pidst == -1 && errno == EINTR); + + if (!WIFEXITED (status)) + mutt_error (_("Slrnface abnormaly exited, code %d."), status); + else + { + char *message; + + switch (WEXITSTATUS (status)) + { + case 0: /* All fine, open the pipe */ + slrnface_fd = open (fifo, O_WRONLY, 0600); + write (slrnface_fd, "start\n", sizeof "start"); + goto clean_face; + case 1: message = "couldn't connect to display"; + break; + case 2: message = "WINDOWID not found in environment"; + break; + case 3: message = "couldn't find controlling terminal"; + break; + case 4: message = "terminal doesn't export width and height"; + break; + case 5: message = "cannot open FIFO"; + break; + case 6: message = "fork() failed"; + break; + case 10: message = "executable not found"; + break; + default: message = "unknown error"; + } + mutt_error (_("Slrnface failed: %s."), message); + } + } + +clean_face: + unlink (fifo); + free (fifo); +} + +void mutt_stop_slrnface(void) +{ + if (slrnface_fd >= 0) + close(slrnface_fd); + slrnface_fd = -1; + + /* FIFO has been unlinked in the startup function. */ +} diff -urp ../MUTT/mutt/init.h mutt/init.h --- ../MUTT/mutt/init.h 2004-07-21 13:33:02.000000000 +0200 +++ mutt/init.h 2004-07-21 13:33:47.000000000 +0200 @@ -2736,6 +2736,12 @@ struct option_t MuttVars[] = { ** Controls whether mutt writes out the Bcc header when preparing ** messages to be sent. Exim users may wish to use this. */ + { "xface", DT_BOOL, R_NONE, OPTXFACE, 0 }, + /* + ** .pp + ** Controls whether mutt uses slrnface to display X-Faces when run + ** in an X11 terminal emulator. + */ /*--*/ { NULL } }; diff -urp ../MUTT/mutt/main.c mutt/main.c --- ../MUTT/mutt/main.c 2004-06-18 17:24:22.000000000 +0200 +++ mutt/main.c 2004-07-21 13:33:47.000000000 +0200 @@ -905,6 +905,8 @@ int main (int argc, char **argv) mutt_folder_hook (folder); + mutt_start_slrnface(); + if((Context = mx_open_mailbox (folder, ((flags & M_RO) || option (OPTREADONLY)) ? M_READONLY : 0, NULL)) || !explicit_folder) { @@ -913,6 +915,8 @@ int main (int argc, char **argv) FREE (&Context); } mutt_endwin (Errorbuf); + + mutt_stop_slrnface(); } exit (0); diff -urp ../MUTT/mutt/mutt.h mutt/mutt.h --- ../MUTT/mutt/mutt.h 2004-07-21 13:33:02.000000000 +0200 +++ mutt/mutt.h 2004-07-21 13:33:47.000000000 +0200 @@ -435,6 +435,7 @@ enum OPTWRAP, OPTWRAPSEARCH, OPTWRITEBCC, /* write out a bcc header? */ + OPTXFACE, OPTXMAILER, OPTCRYPTUSEGPGME, @@ -577,6 +578,7 @@ typedef struct envelope BUFFER *spam; LIST *references; /* message references (in reverse order) */ LIST *in_reply_to; /* in-reply-to header content */ + LIST *x_face; /* X-Face header content */ LIST *userhdrs; /* user defined headers */ } ENVELOPE; diff -urp ../MUTT/mutt/muttlib.c mutt/muttlib.c --- ../MUTT/mutt/muttlib.c 2004-07-18 01:25:28.000000000 +0200 +++ mutt/muttlib.c 2004-07-21 13:33:47.000000000 +0200 @@ -651,6 +651,7 @@ void mutt_free_envelope (ENVELOPE **p) FREE (&(*p)->date); mutt_free_list (&(*p)->references); mutt_free_list (&(*p)->in_reply_to); + mutt_free_list (&(*p)->x_face); mutt_free_list (&(*p)->userhdrs); FREE (p); } diff -urp ../MUTT/mutt/pager.c mutt/pager.c --- ../MUTT/mutt/pager.c 2004-07-18 01:25:28.000000000 +0200 +++ mutt/pager.c 2004-07-21 13:36:34.000000000 +0200 @@ -1441,6 +1441,66 @@ upNLines (int nlines, struct line_t *inf return cur; } +static void +mutt_display_xface (HEADER *hdr) +{ + LIST *face; + char buf[2000]; + + if (slrnface_fd < 0) + return; + + if (!hdr) + return; + + face = hdr->env->x_face; + + if (face == NULL || face->data == NULL) + write(slrnface_fd, "clear\n", sizeof "clear"); + else + do { + int len; + + len = snprintf (buf, sizeof (buf), "xface %s\n", face->data); + if (len <= sizeof (buf)) + { + write (slrnface_fd, buf, len); + break; + } + /* + * slrnface will ignore X-Faces larger than approx. 2000 chars, so + * try the next one, if it exists. + */ + } while (face = face->next); +} + +static void +mutt_clear_xface (void) +{ + if (slrnface_fd < 0) + return; + + write(slrnface_fd, "clear\n", sizeof "clear"); +} + +static void +mutt_suppress_xface (void) +{ + if (slrnface_fd < 0) + return; + + write(slrnface_fd, "suppress\n", sizeof "suppress"); +} + +static void +mutt_show_xface (void) +{ + if (slrnface_fd < 0) + return; + + write(slrnface_fd, "show\n", sizeof "show"); +} + static struct mapping_t PagerHelp[] = { { N_("Exit"), OP_EXIT }, { N_("PrevPg"), OP_PREV_PAGE }, @@ -1545,6 +1605,9 @@ mutt_pager (const char *banner, const ch snprintf (helpstr, sizeof (helpstr), "%s %s", tmphelp, buffer); } + if (IsHeader (extra)) + mutt_display_xface(extra->hdr); + while (ch != -1) { mutt_curs_set (0); @@ -2067,7 +2130,9 @@ search_next: if (! InHelp) { InHelp = 1; + mutt_suppress_xface (); mutt_help (MENU_PAGER); + mutt_show_xface (); redraw = REDRAW_FULL; InHelp = 0; } @@ -2383,59 +2448,71 @@ CHECK_IMAP_ACL(IMAP_ACL_WRITE); case OP_MAIL: CHECK_MODE(IsHeader (extra) && !IsAttach (extra)); CHECK_ATTACH; + mutt_suppress_xface (); ci_send_message (0, NULL, NULL, extra->ctx, NULL); + mutt_show_xface (); redraw = REDRAW_FULL; break; case OP_REPLY: CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra)); CHECK_ATTACH; + mutt_suppress_xface(); if (IsMsgAttach (extra)) mutt_attach_reply (extra->fp, extra->hdr, extra->idx, extra->idxlen, extra->bdy, SENDREPLY); else ci_send_message (SENDREPLY, NULL, NULL, extra->ctx, extra->hdr); + mutt_show_xface (); redraw = REDRAW_FULL; break; case OP_RECALL_MESSAGE: CHECK_MODE(IsHeader (extra) && !IsAttach(extra)); CHECK_ATTACH; + mutt_suppress_xface(); ci_send_message (SENDPOSTPONED, NULL, NULL, extra->ctx, extra->hdr); + mutt_show_xface (); redraw = REDRAW_FULL; break; case OP_GROUP_REPLY: CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra)); CHECK_ATTACH; + mutt_suppress_xface(); if (IsMsgAttach (extra)) mutt_attach_reply (extra->fp, extra->hdr, extra->idx, extra->idxlen, extra->bdy, SENDREPLY|SENDGROUPREPLY); else ci_send_message (SENDREPLY | SENDGROUPREPLY, NULL, NULL, extra->ctx, extra->hdr); + mutt_suppress_xface (); redraw = REDRAW_FULL; break; case OP_LIST_REPLY: CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra)); CHECK_ATTACH; + mutt_suppress_xface(); if (IsMsgAttach (extra)) mutt_attach_reply (extra->fp, extra->hdr, extra->idx, extra->idxlen, extra->bdy, SENDREPLY|SENDLISTREPLY); else ci_send_message (SENDREPLY | SENDLISTREPLY, NULL, NULL, extra->ctx, extra->hdr); + mutt_show_xface (); redraw = REDRAW_FULL; break; case OP_FORWARD_MESSAGE: CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra)); CHECK_ATTACH; + mutt_suppress_xface(); if (IsMsgAttach (extra)) mutt_attach_forward (extra->fp, extra->hdr, extra->idx, extra->idxlen, extra->bdy); else ci_send_message (SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr); + mutt_show_xface (); redraw = REDRAW_FULL; break; @@ -2485,7 +2562,9 @@ CHECK_IMAP_ACL(IMAP_ACL_WRITE); break; case OP_SHELL_ESCAPE: + mutt_suppress_xface (); mutt_shell_escape (); + mutt_show_xface (); MAYBE_REDRAW (redraw); break; @@ -2644,5 +2723,6 @@ CHECK_IMAP_ACL(IMAP_ACL_DELETE); FREE (&lineInfo); if (index) mutt_menuDestroy(&index); + mutt_clear_xface (); return (rc != -1 ? rc : 0); } diff -urp ../MUTT/mutt/parse.c mutt/parse.c --- ../MUTT/mutt/parse.c 2004-07-21 13:33:02.000000000 +0200 +++ mutt/parse.c 2004-07-21 13:33:47.000000000 +0200 @@ -85,6 +85,27 @@ static char *read_rfc822_line (FILE *f, /* not reached */ } +static LIST *mutt_add_x_face (LIST *lst, char *face) +{ + LIST *n; + + n = safe_malloc(sizeof(LIST)); + n->data = safe_strdup(face); + n->next = NULL; + + if (lst) + { + LIST *l; + + for(l = lst; l->next; l = l->next); + l->next = n; + } + else + lst = n; + + return lst; +} + static LIST *mutt_parse_references (char *s, int in_reply_to) { LIST *t, *lst = NULL; @@ -1231,6 +1252,11 @@ int mutt_parse_rfc822_line (ENVELOPE *e, e->x_label = safe_strdup(p); matched = 1; } + else if (ascii_strcasecmp (line+1, "-face") == 0) + { + e->x_face = mutt_add_x_face (e->x_face, p); + matched = 1; + } default: break; diff -urp ../MUTT/mutt/sendlib.c mutt/sendlib.c --- ../MUTT/mutt/sendlib.c 2004-07-21 13:33:02.000000000 +0200 +++ mutt/sendlib.c 2004-07-21 13:37:16.000000000 +0200 @@ -1697,6 +1697,15 @@ int mutt_write_rfc822_header (FILE *fp, } } + /* Add X-Face headers */ + if (env->x_face) + { + LIST *face; + + for (face = env->x_face; face; face = face->next) + fprintf (fp, "X-Face: %s\n", face->data); + } + if (mode == 0 && !privacy && option (OPTXMAILER) && !has_agent) { /* Add a vanity header */