diff --git a/.gitattributes b/.gitattributes
index 11d140debdbd96b49c6004f7cefdb4da8db33a7b..db95198945321a7b8bb79c0c7ad522caa0489b68 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -158,6 +158,8 @@ testfont binary
 /src/modules/_Crypto/rc4.c foreign_ident
 /src/modules/_Crypto/test_crypto.pike foreign_ident
 /src/modules/_Image_JPEG/acconfig.h foreign_ident
+/src/modules/_Image_XFace/acconfig.h foreign_ident
+/src/modules/_Image_XFace/image_xface.c foreign_ident
 /src/modules/call_out/call_out.c foreign_ident
 /src/modules/call_out/test_co.pike foreign_ident
 /src/modules/dynamic_module_makefile.in foreign_ident
diff --git a/src/modules/_Image_XFace/.cvsignore b/src/modules/_Image_XFace/.cvsignore
new file mode 100644
index 0000000000000000000000000000000000000000..4c4abb584f6d9a7910fed717c046546ed81175a2
--- /dev/null
+++ b/src/modules/_Image_XFace/.cvsignore
@@ -0,0 +1,14 @@
+.pure
+Makefile
+config.log
+config.status
+configure
+dependencies
+linker_options
+modlist_headers
+modlist_segment
+module_testsuite
+stamp-h
+stamp-h.in
+config.h
+config.h.in 
diff --git a/src/modules/_Image_XFace/.gitignore b/src/modules/_Image_XFace/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e9be9e87737786aa2ee941b8904d5d467fc32258
--- /dev/null
+++ b/src/modules/_Image_XFace/.gitignore
@@ -0,0 +1,14 @@
+/.pure
+/Makefile
+/config.log
+/config.status
+/configure
+/dependencies
+/linker_options
+/modlist_headers
+/modlist_segment
+/module_testsuite
+/stamp-h
+/stamp-h.in
+/config.h
+/config.h.in
diff --git a/src/modules/_Image_XFace/Makefile.in b/src/modules/_Image_XFace/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..a2a365050237abba9e7bac89e517695a2e25d362
--- /dev/null
+++ b/src/modules/_Image_XFace/Makefile.in
@@ -0,0 +1,7 @@
+SRCDIR=@srcdir@
+VPATH=@srcdir@:@srcdir@/../..:../..
+OBJS=image_xface.o
+MODULE_LDFLAGS=@LDFLAGS@ @LIBS@
+
+@dynamic_module_makefile@
+@dependencies@
diff --git a/src/modules/_Image_XFace/acconfig.h b/src/modules/_Image_XFace/acconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..038445ef0bf2014d73fc8a737dcc3c432466998c
--- /dev/null
+++ b/src/modules/_Image_XFace/acconfig.h
@@ -0,0 +1,10 @@
+/*
+ * $Id: acconfig.h,v 1.1 1998/02/13 18:57:22 marcus Exp $
+ */
+
+@TOP@
+@BOTTOM@
+
+/* Define this if you have -lgmp */
+#undef HAVE_LIBGMP
+
diff --git a/src/modules/_Image_XFace/configure.in b/src/modules/_Image_XFace/configure.in
new file mode 100755
index 0000000000000000000000000000000000000000..edcb8499932a70103f5a6923455c2a010b19d410
--- /dev/null
+++ b/src/modules/_Image_XFace/configure.in
@@ -0,0 +1,17 @@
+AC_INIT(image_xface.c)
+AC_CONFIG_HEADER(config.h)
+AC_ARG_WITH(gmp,     [  --with(out)-gmp        Support bignums],[],[with_gmp=yes])
+
+sinclude(../module_configure.in)
+
+if test x$with_gmp = xyes ; then
+  AC_CHECK_HEADERS(gmp.h)
+  if test $ac_cv_header_gmp_h = yes ; then
+    AC_CHECK_LIB(gmp, mpz_init)
+  fi
+fi
+
+AC_OUTPUT(Makefile,echo FOO >stamp-h )
+
+
+
diff --git a/src/modules/_Image_XFace/image_xface.c b/src/modules/_Image_XFace/image_xface.c
new file mode 100644
index 0000000000000000000000000000000000000000..673fde3c195cd5f14a13d3ab197cf33911a56a20
--- /dev/null
+++ b/src/modules/_Image_XFace/image_xface.c
@@ -0,0 +1,308 @@
+#include "global.h"
+RCSID("$Id: image_xface.c,v 1.1 1998/02/13 18:57:23 marcus Exp $");
+
+#include "config.h"
+
+#if !defined(HAVE_LIBGMP)
+#undef HAVE_GMP_H
+#endif
+
+#ifdef HAVE_GMP_H
+
+#include <gmp.h>
+
+#endif /* HAVE_GMP_H */
+
+#include "pike_macros.h"
+#include "object.h"
+#include "constants.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "threads.h"
+#include "array.h"
+#include "mapping.h"
+#include "error.h"
+#include "stralloc.h"
+#include "dynamic_buffer.h"
+
+#ifdef HAVE_GMP_H
+
+#include "../Image/image.h"
+
+static struct program *image_program=NULL;
+
+#endif /* HAVE_GMP_H */
+
+#ifdef HAVE_GMP_H
+
+/*
+**! module Image
+**! submodule XFace
+**!
+**! note
+**!	This module uses <tt>libgmp</tt>.
+*/
+
+
+static unsigned char tab[] = {
+  0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0xc7, 0xfb, 0xa0, 0xe8, 0xa0, 0xf0,
+  0x00, 0xd8, 0xf0, 0xfb, 0x00, 0x20, 0x00, 0x00, 0xb0, 0xf0, 0xc0, 0xfe,
+  0x00, 0x00, 0x00, 0x80, 0x00, 0xb8, 0xa2, 0xf4, 0x00, 0x00, 0x00, 0xb0,
+  0x00, 0x50, 0xff, 0xff, 0x00, 0x20, 0x00, 0xa0, 0x80, 0xfc, 0xf3, 0xff,
+  0x08, 0x80, 0x01, 0x93, 0xf0, 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0xd8, 0xf8, 0xff, 0xff, 0xf2, 0x2a, 0xe0, 0xf8, 0xea, 0xe2, 0xeb, 0xbc,
+  0xff, 0xff, 0xfa, 0xf8, 0xfe, 0xff, 0xfe, 0xfe, 0xa0, 0xf0, 0x80, 0xf0,
+  0xf0, 0xfa, 0xd9, 0xfb, 0xfe, 0xff, 0xfa, 0xb8, 0xfa, 0xff, 0xf0, 0xf8,
+  0xf0, 0xfa, 0xc0, 0xf8, 0xf2, 0xfa, 0xef, 0xfe, 0xfe, 0xff, 0xb0, 0xf0,
+  0xdf, 0xff, 0xef, 0xfd, 0xf0, 0xf2, 0xeb, 0xfc, 0xf2, 0xfe, 0xff, 0xff,
+  0xe6, 0xfd, 0x6a, 0xa4, 0xf8, 0xfe, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xa0,
+  0xfa, 0xfe, 0x80, 0xfb, 0x28, 0x00, 0xa0, 0xf0, 0xe0, 0x45, 0x90, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0xf0, 0xfa, 0x18, 0xeb, 0x29, 0x8e, 0x00, 0xa0,
+  0xf8, 0xed, 0x30, 0xe0, 0xf0, 0xf0, 0x00, 0xf0, 0xf0, 0xf8, 0x21, 0xf1,
+  0xa0, 0xa8, 0xa0, 0xf0, 0xf2, 0xff, 0xe1, 0xfb, 0xa0, 0x80, 0x08, 0x00,
+  0xf0, 0xf0, 0x00, 0x10, 0xa0, 0x20, 0x20, 0x80, 0xf2, 0xff, 0xf9, 0xf1,
+  0x52, 0x02, 0xfa, 0xfa, 0xff, 0x7f, 0xfb, 0xff, 0xfe, 0xef, 0xff, 0xfe,
+  0xff, 0xff, 0xde, 0xff, 0xf0, 0xbf, 0xeb, 0xfa, 0xf2, 0xfe, 0xfe, 0xfb,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xee, 0xfb, 0xfe, 0xf2, 0xf7, 0xff, 0xff,
+  0xee, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xf0, 0xf2, 0xff, 0xff, 0xb9, 0xff,
+  0xf0, 0xf7, 0xff, 0xfb, 0xf6, 0xff, 0xff, 0xff, 0xf2, 0xff, 0xb3, 0xf0,
+  0xf2, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0xd0, 0xa0, 0x40, 0x40, 0xf0,
+  0x20, 0x00, 0x00, 0x30, 0x80, 0x60, 0x00, 0xf0, 0x04, 0xc0, 0x00, 0x00,
+  0xa0, 0xf0, 0x02, 0x10, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x30, 0xf0,
+  0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x80, 0xa0,
+  0x80, 0xa8, 0xf5, 0xf0, 0x00, 0x80, 0x08, 0x00, 0x10, 0x00, 0x62, 0x30,
+  0x04, 0x00, 0x11, 0x00, 0xf0, 0xa8, 0xff, 0xfb, 0x40, 0x00, 0x00, 0xf0,
+  0xfe, 0xfa, 0xdb, 0xff, 0xf2, 0x7c, 0xa0, 0xf0, 0xfe, 0xef, 0xa9, 0xf2,
+  0xb0, 0xf0, 0x80, 0xf0, 0xf2, 0xfa, 0xf9, 0xfb, 0xa4, 0x70, 0xb0, 0xb0,
+  0xf2, 0xfe, 0xf1, 0xf0, 0xf0, 0x5f, 0x20, 0xf2, 0xf2, 0xff, 0xef, 0xee,
+  0xe2, 0xb7, 0xa0, 0xf0, 0xff, 0xff, 0xfb, 0xff, 0xf2, 0xf6, 0x1b, 0xfa,
+  0xf0, 0xfe, 0xfb, 0xfa, 0xe0, 0xf0, 0x29, 0xb0, 0xf8, 0xff, 0xff, 0xff,
+  0x00, 0x40, 0x00, 0xc0, 0x62, 0xea, 0x80, 0xb0, 0x80, 0x10, 0x80, 0xf0,
+  0xe2, 0x36, 0xb0, 0xf0, 0x40, 0x00, 0x00, 0x00, 0xd0, 0xf2, 0x00, 0x10,
+  0xa0, 0x00, 0xa9, 0x80, 0xf0, 0xfe, 0x30, 0xf0, 0x80, 0x70, 0x00, 0x00,
+  0xf0, 0x82, 0x00, 0x00, 0x20, 0x24, 0xb0, 0xf0, 0xf0, 0xfe, 0xf3, 0xfb,
+  0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x60, 0x64, 0xf3, 0xa0,
+  0xf3, 0xfe, 0xfb, 0xfb, 0x00, 0x00, 0xe8, 0xfa, 0xff, 0xbf, 0xff, 0xff,
+  0x62, 0x90, 0xf2, 0xfa, 0xfe, 0xbf, 0xfb, 0xff, 0x50, 0x11, 0xe5, 0xfe,
+  0xfe, 0xff, 0xff, 0xff, 0xf0, 0x20, 0xfb, 0xfe, 0xf2, 0xff, 0xf9, 0xff,
+  0x70, 0x67, 0xfb, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xf0, 0x37, 0xf1, 0xf2,
+  0xfe, 0xff, 0xfb, 0xff, 0xf0, 0xf3, 0xfb, 0xff, 0xf6, 0xfe, 0xff, 0xff,
+  0xc0, 0x30, 0xb9, 0xf0, 0xfe, 0xff, 0xff, 0xff, 0xec, 0xce, 0x00, 0x98,
+  0xea, 0xfe, 0xaf, 0xdf, 0x0e, 0xcc, 0x0f, 0x9f, 0xfe, 0xff, 0xff, 0xff,
+  0x0a, 0x00, 0x00, 0x00, 0xa0, 0x00, 0xf0, 0xac, 0x1f, 0x02, 0x82, 0x9e,
+  0x0f, 0x42, 0x0c, 0xfa, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x0c, 0xcc, 0xbc,
+  0x0e, 0x0a, 0xac, 0xcf, 0x8f, 0xce, 0xfc, 0xff, 0x0f, 0x10, 0x00, 0x04,
+  0x82, 0x04, 0x80, 0xa8, 0x0e, 0x4a, 0x0a, 0x0a, 0xcc, 0xda, 0x9f, 0xff,
+  0x0f, 0x6e, 0x4f, 0x20, 0x80, 0x0e, 0xf6, 0x75, 0x01, 0x08, 0x8e, 0x9f,
+  0x8f, 0xff, 0xff, 0xff, 0x0f, 0x02, 0x00, 0x08, 0x28, 0x4c, 0xf7, 0xcf,
+  0x8f, 0x88, 0x88, 0x88, 0xa8, 0x88, 0x88, 0x8c, 0x88, 0x88, 0x88, 0x8c,
+  0x88, 0x88, 0xc8, 0x8c, 0x88, 0x8c, 0x88, 0x8c, 0x8c, 0x8c, 0xcc, 0xc8,
+  0x88, 0x08, 0x88, 0x88, 0xe8, 0x88, 0x88, 0xe8, 0x0a, 0x00, 0x0f, 0x00,
+  0x09, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0f, 0x20, 0x77, 0x02, 0x8b, 0x00,
+  0x0f, 0x00, 0x2f, 0x22, 0x0f, 0x80, 0x07, 0x0f, 0x5f, 0x57, 0x2f, 0xea,
+  0x7f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x09, 0x88, 0x08, 0x00, 0x88, 0xb3,
+  0x0b, 0x80, 0x0a, 0xf0, 0x0f, 0x80, 0x00, 0xf0, 0x0b, 0x00, 0x2f, 0xaf,
+  0xcf, 0xfb, 0xff, 0xff, 0x2f, 0xff, 0x8f, 0xf3, 0xbf, 0xff, 0x1f, 0xff,
+  0x0f, 0x00, 0x0b, 0x00, 0x00, 0x80, 0x0a, 0x08, 0x0e, 0x00, 0x08, 0x84,
+  0x0f, 0x88, 0x08, 0xea, 0x0f, 0x80, 0x2f, 0xa8, 0x8e, 0xff, 0x0f, 0xea,
+  0x0e, 0xab, 0x2f, 0xfb, 0x2f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x04,
+  0x0a, 0x80, 0x08, 0xea, 0x8b, 0x80, 0x4a, 0xff, 0x2f, 0xa0, 0x00, 0xfb,
+  0x0b, 0x02, 0x0f, 0x8e, 0x0f, 0xee, 0x0f, 0xdf, 0x0f, 0xeb, 0x0f, 0xff,
+  0x2f, 0xeb, 0x0b, 0xff, 0x0f, 0x88, 0x0c, 0xec, 0x8f, 0xae, 0xaa, 0xae,
+  0xee, 0x0f, 0x08, 0x08, 0x88, 0x0f, 0x8c, 0xcf, 0xff, 0x2f, 0x44
+};
+
+/*
+00   01   02   10   20   30   40   11   21   31   41   12   22   32   42
+0000 4096 4224 4228 4740 4804 5060 6084 6116 6124 6156 6220 6222 6223 6227
+*/
+
+static int taboffs[] = { 0, 4740, 4228, 5060, 4224, 6222, 6220, 6227,
+			 4096, 6116, 6084, 6156 };
+
+static void xform(unsigned char *i, unsigned char *o)
+{
+  int x, y, X, Y, p, n;
+
+  for(y=0; y<48; y++)
+    for(x=0; x<48; x++) {
+      n=0;
+      for(X=(x<3? 1:x-2); X<x+3; X++)
+	for(Y=(y<3? 1:y-2); Y<=y; Y++)
+	  if((Y<y || X<x) && X<=48)
+	    n = (n<<1)|i[Y*48+X];
+
+      if((p=x)==47)
+	p = 3;
+      else if(x>2)
+	p = 0;
+      if(y==1)
+	p += 4;
+      else if(y==2)
+	p += 8;
+      n += taboffs[p];
+      *o++ ^= (tab[n>>3]>>(n&7))&1;
+    }
+}
+
+static unsigned int topprob[4][6] = {
+  {1, 255, 251, 0, 4, 251},
+  {1, 255, 200, 0, 55, 200},
+  {33, 223, 159, 0, 64, 159},
+  {131, 0, 0, 0, 125, 131}
+};
+
+static unsigned int botprob[32] = {
+  0, 0, 38, 0, 38, 38, 13, 152,
+  38, 76, 13, 165, 13, 178, 6, 230,
+  38, 114, 13, 191, 13, 204, 6, 236,
+  13, 217, 6, 242, 5, 248, 3, 253
+};
+
+static int pop(mpz_t val, unsigned int *p)
+{
+  unsigned long int n;
+  int r = 0;
+  mpz_t dum;
+
+  mpz_init(dum);
+  n = mpz_fdiv_qr_ui(val, dum, val, 256);
+  mpz_clear(dum);
+  while(n<p[1] || n>=p[0]+p[1]) {
+    r++;
+    p += 2;
+  }
+  mpz_mul_ui(val, val, *p++);
+  mpz_add_ui(val, val, n-*p);
+  return r;
+}
+
+static void popg(mpz_t val, unsigned char *face, int s)
+{
+  if(s>=4) {
+    s>>=1;
+    popg(val, face, s);
+    popg(val, face+s, s);
+    popg(val, face+s*48, s);
+    popg(val, face+s*49, s);
+  } else {
+    int p = pop(val, botprob);
+    face[0]=p&1; p>>=1;
+    face[1]=p&1; p>>=1;
+    face[48]=p&1; p>>=1;
+    face[49]=p&1;
+  }
+}
+
+static void uncomp(mpz_t val, unsigned char *face, int s, int l)
+{
+  switch(pop(val, topprob[l])) {
+  case 0:
+    popg(val, face, s);
+    break;
+  case 1:
+    s>>=1;
+    l++;
+    uncomp(val, face, s, l);
+    uncomp(val, face+s, s, l);
+    uncomp(val, face+s*48, s, l);
+    uncomp(val, face+s*49, s, l);
+    break;
+  }
+}
+
+static void decodeface(char *data, INT32 len, rgb_group *out)
+{
+  unsigned char face[48][48];
+  int i, j;
+  mpz_t val;
+
+  mpz_init(val);
+  mpz_set_ui(val, 0);
+  while(len--)
+    if(*data>='!' && *data<='~') {
+      mpz_mul_ui(val, val, 94);
+      mpz_add_ui(val, val, *data++-'!');
+    } else
+      data++;
+  memset(face, 0, sizeof(face));
+  for(i=0; i<3; i++)
+    for(j=0; j<3; j++)
+      uncomp(val, &face[i*16][j*16], 16, 0);
+  mpz_clear(val);
+  xform((unsigned char *)face, (unsigned char *)face);
+  for(i=0; i<48; i++)
+    for(j=0; j<48; j++) {
+      if(face[i][j])
+	out->r = out->g = out->b = 0;
+      else
+	out->r = out->g = out->b = ~0;
+      out++;
+    }
+}
+
+/*
+**! method object decode(string data)
+**! method object decode(string data, mapping options)
+**! 	Decodes an X-Face image. 
+**!
+**!     The <tt>options</tt> argument may be a mapping
+**!	containing zero options.
+**!
+*/
+
+static void image_xface_decode(INT32 args)
+{
+  struct object *o;
+  struct image *img;
+
+  if(args<1 || sp[-args].type!=T_STRING)
+    error("Image.XFace.decode: Illegal arguments\n");
+
+  o=clone_object(image_program,0);
+  img=(struct image*)get_storage(o,image_program);
+  if (!img) error("image no image? foo?\n"); /* should never happen */
+  img->img=malloc(sizeof(rgb_group)*48*48);
+  if (!img->img) {
+    free_object(o);
+    error("Image.XFace.decode: out of memory\n");
+  }
+  img->xsize=48;
+  img->ysize=48;
+  decodeface(sp[-args].u.string->str, sp[-args].u.string->len, img->img);
+  pop_n_elems(args);
+  push_object(o);
+}
+
+#endif /* HAVE_GMP_H */
+
+/*** module init & exit & stuff *****************************************/
+
+void pike_module_exit(void)
+{
+}
+
+void pike_module_init(void)
+{
+#ifdef HAVE_GMP_H
+   push_string(make_shared_string("Image"));
+   push_int(0);
+   SAFE_APPLY_MASTER("resolv",2);
+   if (sp[-1].type==T_OBJECT) 
+   {
+      push_string(make_shared_string("image"));
+      f_index(2);
+      image_program=program_from_svalue(sp-1);
+   }
+   pop_n_elems(1);
+
+   if (image_program)
+   {
+      add_function("decode",image_xface_decode,
+		   "function(string,void|mapping(string:int):object)",0);
+   }
+
+#endif /* HAVE_GMP_H */
+
+}
+
diff --git a/src/modules/_Image_XFace/testsuite.in b/src/modules/_Image_XFace/testsuite.in
new file mode 100644
index 0000000000000000000000000000000000000000..1deeae01981e2d12f8eb6a5c49caa52a39368f6b
--- /dev/null
+++ b/src/modules/_Image_XFace/testsuite.in
@@ -0,0 +1,3 @@
+cond([[ master()->resolv("_Image_XFace")->decode ]],
+[[
+]])