1--- globals.h.orig	Sat Aug 24 10:10:36 2002
2+++ globals.h	Thu May 30 23:13:46 2002
3@@ -171,6 +171,8 @@
4 WHERE ALIAS *Aliases INITVAL (0);
5 WHERE LIST *UserHeader INITVAL (0);
6
7+WHERE int slrnface_fd INITVAL (-1);
8+
9 #ifdef DEBUG
10 WHERE FILE *debugfile INITVAL (0);
11 WHERE int debuglevel INITVAL (0);
12--- init.c.orig	Mon Feb 11 10:58:54 2002
13+++ init.c	Sat Aug 24 07:28:13 2002
14@@ -47,6 +47,8 @@
15 #include <string.h>
16 #include <sys/utsname.h>
17 #include <errno.h>
18+#include <sys/types.h>
19+#include <fcntl.h>
20 #include <sys/wait.h>
21
22 void toggle_quadoption (int opt)
23@@ -1966,4 +1968,132 @@
24     if (c->func == mutt_parse_hook && ascii_strcasecmp (c->name, name) == 0)
25       return c->data;
26   return 0;
27+}
28+
29+void mutt_start_slrnface(void)
30+{
31+  char *fifo;
32+  int pathlen, status;
33+  pid_t pid, pidst;
34+  struct utsname u;
35+
36+  if (!option(OPTXFACE))
37+    return;
38+
39+  /*
40+   * If we don't have display, there's no point. The user probably knows,
41+   * so fail silently.
42+   */
43+  if (!getenv("DISPLAY"))
44+    return;
45+  /* If there is no WINDOWID, complain. */
46+  if (!getenv ("WINDOWID"))
47+  {
48+    mutt_error (_("Cannot run slrnface: WINDOWID not found in environment."));
49+    return;
50+  }
51+
52+  uname (&u);
53+  pathlen = strlen (Homedir) + sizeof("/.slrnfaces/")
54+            + strlen (u.nodename) + 30;
55+  fifo = safe_malloc (pathlen);
56+  sprintf (fifo, "%s/.slrnfaces", Homedir);
57+  if (mkdir (fifo, 0700))
58+  {
59+    if (errno != EEXIST)
60+    {
61+      mutt_error (_("Cannot run slrnface: failed to create %s: %s."),
62+	  	  fifo, strerror(errno));
63+      return;
64+    }
65+  }
66+  else
67+  {
68+    FILE *fp;
69+
70+    /* We'll abuse fifo filename memory here. It's long enough. */
71+    sprintf (fifo, "%s/.slrnfaces/README", Homedir);
72+    if ((fp = fopen (fifo, "w")) != NULL)
73+    {
74+      fputs (_(
75+"This directory is used to create named pipes for communication between\n"
76+"slrnface and its parent process. It should normally be empty because\n"
77+"the pipe is deleted right after it has been opened by both processes.\n\n"
78+"File names generated by slrnface have the form \"hostname.pid\". It is\n"
79+"probably an error if they linger here longer than a fraction of a second.\n\n"
80+"However, if the directory is mounted from an NFS server, you might see\n"
81+"special files created by your NFS server while slrnface is running.\n"
82+"Do not try to remove them.\n"), fp);
83+      fclose (fp);
84+    }
85+  }
86+
87+  status = snprintf (fifo, pathlen, "%s/.slrnfaces/%s.%ld", Homedir,
88+	  	     u.nodename, (long)getpid());
89+  if (status < 0)
90+    goto clean_face;
91+
92+  unlink (fifo);
93+  if (mkfifo (fifo, 0600) < 0)
94+  {
95+    mutt_error (_("Cannot run slrnface, failed to create %s: %s."), fifo,
96+		strerror(errno));
97+    goto clean_face;
98+  }
99+
100+  pid = fork();
101+  switch (pid)
102+  {
103+    case -1: break;
104+    case 0:  execlp ("slrnface", "slrnface", fifo, (char *)0);
105+	     /* This is child, exit on error. */
106+	     _exit (10);
107+    default: do {
108+	       pidst = waitpid (pid, &status, 0);
109+	     } while (pidst == -1 && errno == EINTR);
110+
111+	     if (!WIFEXITED (status))
112+	       mutt_error (_("Slrnface abnormaly exited, code %d."), status);
113+	     else
114+	     {
115+	       char *message;
116+
117+	       switch (WEXITSTATUS (status))
118+	       {
119+		 case 0: /* All fine, open the pipe */
120+			 slrnface_fd = open (fifo, O_WRONLY, 0600);
121+			 write (slrnface_fd, "start\n", sizeof "start");
122+			 goto clean_face;
123+		 case 1: message = "couldn't connect to display";
124+			 break;
125+		 case 2: message = "WINDOWID not found in environment";
126+			 break;
127+		 case 3: message = "couldn't find controlling terminal";
128+			 break;
129+		 case 4: message = "terminal doesn't export width and height";
130+			 break;
131+		 case 5: message = "cannot open FIFO";
132+			 break;
133+		 case 6: message = "fork() failed";
134+			 break;
135+		 case 10: message = "executable not found";
136+			  break;
137+		 default: message = "unknown error";
138+	       }
139+	       mutt_error (_("Slrnface failed: %s."), message);
140+	     }
141+  }
142+
143+clean_face:
144+  unlink (fifo);
145+  free (fifo);
146+}
147+
148+void mutt_stop_slrnface(void)
149+{
150+  if (slrnface_fd >= 0)
151+    close(slrnface_fd);
152+  slrnface_fd = -1;
153+
154+  /* FIFO has been unlinked in the startup function. */
155 }
156--- init.h.orig	Thu Apr 25 15:26:37 2002
157+++ init.h	Thu May 30 23:13:46 2002
158@@ -2366,6 +2366,12 @@
159   ** Controls whether mutt writes out the Bcc header when preparing
160   ** messages to be sent.  Exim users may wish to use this.
161   */
162+  { "xface",		DT_BOOL, R_NONE, OPTXFACE, 0 },
163+  /*
164+  ** .pp
165+  ** Controls whether mutt uses slrnface to display X-Faces when run
166+  ** in an X11 terminal emulator.
167+  */
168   /*--*/
169   { NULL }
170 };
171--- main.c.orig	Sat Aug 24 10:11:53 2002
172+++ main.c	Thu May 30 23:13:46 2002
173@@ -835,6 +835,8 @@
174
175     mutt_folder_hook (folder);
176
177+    mutt_start_slrnface();
178+
179     if((Context = mx_open_mailbox (folder, ((flags & M_RO) || option (OPTREADONLY)) ? M_READONLY : 0, NULL))
180        || !explicit_folder)
181     {
182@@ -843,6 +845,8 @@
183 	safe_free ((void **)&Context);
184     }
185     mutt_endwin (Errorbuf);
186+
187+    mutt_stop_slrnface();
188   }
189
190   exit (0);
191--- mutt.h.orig	Sat Aug 24 10:12:08 2002
192+++ mutt.h	Thu May 30 23:13:46 2002
193@@ -410,6 +410,7 @@
194   OPTWRAP,
195   OPTWRAPSEARCH,
196   OPTWRITEBCC,		/* write out a bcc header? */
197+  OPTXFACE,
198   OPTXMAILER,
199
200   /* PGP options */
201@@ -526,6 +527,7 @@
202   char *x_label;
203   LIST *references;		/* message references (in reverse order) */
204   LIST *in_reply_to;		/* in-reply-to header content */
205+  LIST *x_face;			/* X-Face header content */
206   LIST *userhdrs;		/* user defined headers */
207 } ENVELOPE;
208
209--- muttlib.c.orig	Sat Aug 24 10:12:24 2002
210+++ muttlib.c	Thu May 30 23:13:47 2002
211@@ -650,6 +650,7 @@
212   safe_free ((void **) &(*p)->date);
213   mutt_free_list (&(*p)->references);
214   mutt_free_list (&(*p)->in_reply_to);
215+  mutt_free_list (&(*p)->x_face);
216   mutt_free_list (&(*p)->userhdrs);
217   safe_free ((void **) p);
218 }
219--- pager.c.orig	Sat Aug 24 10:12:57 2002
220+++ pager.c	Sat Aug 24 23:39:17 2002
221@@ -1431,6 +1431,66 @@
222   return cur;
223 }
224
225+static void
226+mutt_display_xface (HEADER *hdr)
227+{
228+  LIST *face;
229+  char buf[2000];
230+
231+  if (slrnface_fd < 0)
232+    return;
233+
234+  if (!hdr)
235+    return;
236+
237+  face = hdr->env->x_face;
238+
239+  if (face == NULL || face->data == NULL)
240+    write(slrnface_fd, "clear\n", sizeof "clear");
241+  else
242+    do {
243+      int len;
244+
245+      len = snprintf (buf, sizeof (buf), "xface %s\n", face->data);
246+      if (len <= sizeof (buf))
247+      {
248+	write (slrnface_fd, buf, len);
249+	break;
250+      }
251+      /*
252+       * slrnface will ignore X-Faces larger than approx. 2000 chars, so
253+       * try the next one, if it exists.
254+       */
255+    } while (face = face->next);
256+}
257+
258+static void
259+mutt_clear_xface (void)
260+{
261+  if (slrnface_fd < 0)
262+    return;
263+
264+  write(slrnface_fd, "clear\n", sizeof "clear");
265+}
266+
267+static void
268+mutt_suppress_xface (void)
269+{
270+  if (slrnface_fd < 0)
271+    return;
272+
273+  write(slrnface_fd, "suppress\n", sizeof "suppress");
274+}
275+
276+static void
277+mutt_show_xface (void)
278+{
279+  if (slrnface_fd < 0)
280+    return;
281+
282+  write(slrnface_fd, "show\n", sizeof "show");
283+}
284+
285 static struct mapping_t PagerHelp[] = {
286   { N_("Exit"),	OP_EXIT },
287   { N_("PrevPg"), OP_PREV_PAGE },
288@@ -1535,6 +1595,9 @@
289     snprintf (helpstr, sizeof (helpstr), "%s %s", tmphelp, buffer);
290   }
291
292+  if (IsHeader (extra))
293+    mutt_display_xface(extra->hdr);
294+
295   while (ch != -1)
296   {
297     mutt_curs_set (0);
298@@ -2035,7 +2098,9 @@
299 	if (! InHelp)
300 	{
301 	  InHelp = 1;
302+	  mutt_suppress_xface ();
303 	  mutt_help (MENU_PAGER);
304+	  mutt_show_xface ();
305 	  redraw = REDRAW_FULL;
306 	  InHelp = 0;
307 	}
308@@ -2327,59 +2392,71 @@
309       case OP_MAIL:
310 	CHECK_MODE(IsHeader (extra) && !IsAttach (extra));
311         CHECK_ATTACH;
312+	mutt_suppress_xface ();
313 	ci_send_message (0, NULL, NULL, NULL, NULL);
314+	mutt_show_xface ();
315 	redraw = REDRAW_FULL;
316 	break;
317
318       case OP_REPLY:
319 	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
320         CHECK_ATTACH;
321+	mutt_suppress_xface();
322         if (IsMsgAttach (extra))
323 	  mutt_attach_reply (extra->fp, extra->hdr, extra->idx,
324 			     extra->idxlen, extra->bdy,
325 			     SENDREPLY);
326 	else
327 	  ci_send_message (SENDREPLY, NULL, NULL, extra->ctx, extra->hdr);
328+	mutt_show_xface ();
329 	redraw = REDRAW_FULL;
330 	break;
331
332       case OP_RECALL_MESSAGE:
333 	CHECK_MODE(IsHeader (extra));
334         CHECK_ATTACH;
335+	mutt_suppress_xface();
336 	ci_send_message (SENDPOSTPONED, NULL, NULL, extra->ctx, extra->hdr);
337+	mutt_show_xface ();
338 	redraw = REDRAW_FULL;
339 	break;
340
341       case OP_GROUP_REPLY:
342 	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
343         CHECK_ATTACH;
344+	mutt_suppress_xface();
345         if (IsMsgAttach (extra))
346 	  mutt_attach_reply (extra->fp, extra->hdr, extra->idx,
347 			     extra->idxlen, extra->bdy, SENDREPLY|SENDGROUPREPLY);
348         else
349 	  ci_send_message (SENDREPLY | SENDGROUPREPLY, NULL, NULL, extra->ctx, extra->hdr);
350+	mutt_suppress_xface ();
351 	redraw = REDRAW_FULL;
352 	break;
353
354       case OP_LIST_REPLY:
355 	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
356         CHECK_ATTACH;
357+	mutt_suppress_xface();
358         if (IsMsgAttach (extra))
359 	  mutt_attach_reply (extra->fp, extra->hdr, extra->idx,
360 			     extra->idxlen, extra->bdy, SENDREPLY|SENDLISTREPLY);
361         else
362 	  ci_send_message (SENDREPLY | SENDLISTREPLY, NULL, NULL, extra->ctx, extra->hdr);
363+	mutt_show_xface ();
364 	redraw = REDRAW_FULL;
365 	break;
366
367       case OP_FORWARD_MESSAGE:
368 	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
369         CHECK_ATTACH;
370+	mutt_suppress_xface();
371         if (IsMsgAttach (extra))
372 	  mutt_attach_forward (extra->fp, extra->hdr, extra->idx,
373 			       extra->idxlen, extra->bdy);
374         else
375 	  ci_send_message (SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr);
376+	mutt_show_xface ();
377 	redraw = REDRAW_FULL;
378 	break;
379
380@@ -2428,7 +2505,9 @@
381 	break;
382
383       case OP_SHELL_ESCAPE:
384+	mutt_suppress_xface ();
385 	mutt_shell_escape ();
386+	mutt_show_xface ();
387 	MAYBE_REDRAW (redraw);
388 	break;
389
390@@ -2563,5 +2642,6 @@
391   safe_free ((void **) &lineInfo);
392   if (index)
393     mutt_menuDestroy(&index);
394+  mutt_clear_xface ();
395   return (rc != -1 ? rc : 0);
396 }
397--- parse.c.orig	Tue Jan 29 11:05:20 2002
398+++ parse.c	Thu May 30 23:13:47 2002
399@@ -90,6 +90,27 @@
400   /* not reached */
401 }
402
403+static LIST *mutt_add_x_face (LIST *lst, char *face)
404+{
405+  LIST *n;
406+
407+  n = safe_malloc(sizeof(LIST));
408+  n->data = safe_strdup(face);
409+  n->next = NULL;
410+
411+  if (lst)
412+  {
413+    LIST *l;
414+
415+    for(l = lst; l->next; l = l->next);
416+    l->next = n;
417+  }
418+  else
419+    lst = n;
420+
421+  return lst;
422+}
423+
424 static LIST *mutt_parse_references (char *s, int in_reply_to)
425 {
426   LIST *t, *lst = NULL;
427@@ -1205,6 +1226,11 @@
428     else if (ascii_strcasecmp (line+1, "-label") == 0)
429     {
430       e->x_label = safe_strdup(p);
431+      matched = 1;
432+    }
433+    else if (ascii_strcasecmp (line+1, "-face") == 0)
434+    {
435+      e->x_face = mutt_add_x_face (e->x_face, p);
436       matched = 1;
437     }
438
439--- sendlib.c.orig	Sat Aug 24 00:05:52 2002
440+++ sendlib.c	Sat Aug 24 00:16:54 2002
441@@ -1663,6 +1663,15 @@
442     fputc ('\n', fp);
443   }
444
445+  /* Add X-Face headers */
446+  if (env->x_face)
447+  {
448+    LIST *face;
449+
450+    for (face = env->x_face; face; face = face->next)
451+      fprintf (fp, "X-Face: %s\n", face->data);
452+  }
453+
454   if (mode == 0 && !privacy && option (OPTXMAILER))
455   {
456     /* Add a vanity header */
457