diff -Nadur dpkg-1.15.4/lib/dpkg/dpkg.h dpkg-1.15.4-new/lib/dpkg/dpkg.h
--- dpkg-1.15.4/lib/dpkg/dpkg.h	2009-09-06 10:35:55.000000000 +0300
+++ dpkg-1.15.4-new/lib/dpkg/dpkg.h	2009-09-19 11:58:08.514909283 +0300
@@ -96,6 +96,8 @@
 #define DEFAULTSHELL        "sh"
 #define PAGERENV            "PAGER"
 #define DEFAULTPAGER        "pager"
+#define MERGE2ENV           "MERGE2"
+#define DEFAULTMERGE2       "/usr/bin/merge2"
 
 #define PKGSCRIPTMAXARGS     10
 #define MD5HASHLEN           32
diff -Nadur dpkg-1.15.4/man/dpkg.1 dpkg-1.15.4-new/man/dpkg.1
--- dpkg-1.15.4/man/dpkg.1	2009-09-06 10:35:55.000000000 +0300
+++ dpkg-1.15.4-new/man/dpkg.1	2009-09-19 11:58:08.514909283 +0300
@@ -620,6 +620,8 @@
 .B SHELL
 The program \fBdpkg\fP will execute when starting a new shell.
 .TP
+.B MERGE2
+The program \fBdpkg\fB will execute when the user wants to merge updated conffiles.
 .B COLUMNS
 Sets the number of columns \fBdpkg\fP should use when displaying formatted
 text. Currently only used by \-l.
diff -Nadur dpkg-1.15.4/src/configure.c dpkg-1.15.4-new/src/configure.c
--- dpkg-1.15.4/src/configure.c	2009-09-06 10:35:55.000000000 +0300
+++ dpkg-1.15.4-new/src/configure.c	2009-09-19 12:00:31.740408713 +0300
@@ -58,8 +58,11 @@
 
 static void md5hash(struct pkginfo *pkg, char **hashbuf, const char *fn);
 static void copyfileperm(const char* source, const char* target);
+static char* quotemeta( const char* str );
 static void showdiff(const char* old, const char* new);
-static void suspend(void);
+static const char* mergecommand(void);
+static char mergefiles(const char* old, const char* new);
+static void suspend(const char* old, const char* new);
 static enum conffopt promptconfaction(const char* cfgfile, const char* realold,
 		const char* realnew, int useredited, int distedited,
 		enum conffopt what);
@@ -456,8 +459,29 @@
 		ohshite(_("unable to set mode of new dist conffile `%.250s'"), target);
 }
 
+/* Returns a newly malloc()ated string with shell meta characters
+   escaped. NOTE: you have to free() the resulting string by yourself. */
+char* quotemeta( const char* str )
+{
+	char *res, *dst;
+	unsigned i;
+	unsigned len = strlen(str);
 
+	res = (char*)malloc( len*2 + 1 );
+	if ( !res )
+		ohshite(_("failed allocate a string"));
+	dst = res;
 
+	for ( i=0; i<strlen(str); ++i ) {
+		if ( !((str[i]>='0' && str[i]<='9') ||
+			(str[i]>='A' && str[i]<='Z') ||
+			(str[i]>='a' && str[i]<='z')))
+				*(dst++) = '\\';
+		*(dst++) = str[i];
+	}
+	*dst = 0;
+	return res;
+}
 
 /* Show a diff between two files
  */
@@ -465,18 +489,24 @@
 	int	pid;
 	int	r;
 	int	status;
+	struct sigaction oldintac, newintac;
 
 	if (!(pid=m_fork())) {
 		/* Child process */
 		const char*	p;		/* pager */
 		const char*	s;		/* shell */
 		char		cmdbuf[1024];	/* command to run */
+		char *old_escaped, *new_escaped;
 
 		p=getenv(PAGERENV);
 		if (!p || !*p)
 			p=DEFAULTPAGER;
 
-		sprintf(cmdbuf, DIFF " -Nu %.250s %.250s | %.250s", old, new, p);
+		old_escaped = quotemeta( old );
+		new_escaped = quotemeta( new );
+		sprintf(cmdbuf, DIFF " -Nu %.250s %.250s | %.250s", old_escaped, new_escaped, p);
+		free( new_escaped );
+		free( old_escaped );
 
 		s=getenv(SHELLENV);
 		if (!s || !*s)
@@ -486,10 +516,18 @@
 		ohshite(_("failed to run %s (%.250s)"), DIFF, cmdbuf);
 	}
 
+	/* prevent dpkg from terminating even if the child process is aborted */
+	newintac.sa_handler = SIG_IGN;
+	sigemptyset (&newintac.sa_mask);
+	newintac.sa_flags = 0;
+	sigaction (SIGINT, &newintac, &oldintac);
+
 	/* Parent process */
 	while (((r=waitpid(pid,&status,0))==-1) && (errno==EINTR))
 		;
 
+	sigaction (SIGINT, &oldintac, NULL);
+
 	if (r!=pid) {
 		onerr_abort++;
 		ohshite(_("wait for shell failed"));
@@ -499,10 +537,13 @@
 
 /* Suspend dpkg temporarily
  */
-static void suspend(void) {
+static void suspend(const char* old, const char* new) {
 	const char*	s;
 	int		pid;
 
+	fprintf(stderr,
+		_("\nPackage distributor's new version is '%.250s'.\n"), new );
+
 	s= getenv(NOJOBCTRLSTOPENV);
 	if (s && *s) {
 		/* Do not job control to suspend but fork and start a new shell
@@ -546,11 +587,19 @@
 		const char* realnew, int useredited, int distedited,
 		enum conffopt what) {
 	const char *s;
+	const char *mergestr = "";
+	const char *mergeoptstr = "";
 	int c, cc;
 
 	if (!(what&cfof_prompt))
 		return what;
 
+	if (mergecommand()) {
+		mergestr = _("      M     : merge changes\n");
+		mergeoptstr = _("/M");
+	}
+
+	
 	statusfd_send("status: %s : %s : '%s' '%s' %i %i ",
 			   cfgfile, "conffile-prompt", 
 			   realold, realnew, useredited, distedited);
@@ -609,13 +658,13 @@
 			}
 		}
 
-
 		fprintf(stderr,
 				_("   What would you like to do about it ?  Your options are:\n"
 					"    Y or I  : install the package maintainer's version\n"
 					"    N or O  : keep your currently-installed version\n"
 					"      D     : show the differences between the versions\n"
-					"      Z     : background this process to examine the situation\n"));
+					"%s"
+					"      Z     : background this process to examine the situation\n"), mergestr);
 
 		if (what & cfof_keep)
 			fprintf(stderr, _(" The default action is to keep your current version.\n"));
@@ -624,8 +673,8 @@
 
 		s= strrchr(cfgfile,'/');
 		if (!s || !*++s) s= cfgfile;
-		fprintf(stderr, "*** %s (Y/I/N/O/D/Z) %s ? ",
-				s,
+		fprintf(stderr, "*** %s (Y/I/N/O/D%s/Z) %s ? ",
+				s, mergeoptstr,
 				(what & cfof_keep) ? _("[default=N]") :
 				(what & cfof_install) ? _("[default=Y]") : _("[no default]"));
 
@@ -650,8 +699,15 @@
 		if (cc == 'd')
 			showdiff(realold, realnew);
 
+		if (mergecommand() && cc == 'm') {
+			if (mergefiles(realold, realnew))
+				cc= 'y';
+			else
+				fprintf(stderr, _("\n Command failed or was aborted. Changes were NOT merged.\n"));
+		}
+
 		if (cc == 'z')
-			suspend();
+			suspend(realold, realnew);
 
 	} while (!strchr("yino",cc));
 
@@ -677,3 +733,90 @@
 
 	return what;
 }
+
+/* Returns merge command if merge option is available and NULL otherwise
+ */
+static const char* mergecommand(void) {
+      struct stat stab;
+      const char* m;
+      m = getenv(MERGE2ENV);
+      if (m && *m)
+              return m;
+      else if (!stat(DEFAULTMERGE2,&stab))
+              return DEFAULTMERGE2;
+      return NULL;
+}
+
+/* Let the user merge given files. Returns 1 if the
+ * 'new' was overwritten with a merged file and 0 otherwise
+ */
+static char mergefiles(const char* old, const char* new) {
+      int             pid;
+      int             r;
+      int             status;
+      struct  stat st;
+      char    merged[260];    /* name for merged file */
+      char    cmdbuf[1024];   /* command to run */
+      const char*     m;              /* diff2 merge command */
+      const char*     s;                      /* shell */
+      char *old_escaped, *new_escaped, *merged_escaped;
+      struct sigaction oldintac, newintac;
+
+      sprintf(merged, "%.250s-merged", new);
+
+      s=getenv(SHELLENV);
+      if (!s || !*s)
+              s=DEFAULTSHELL;
+
+      if (!(pid=m_fork())) {
+              /* Child process */
+              m=mergecommand();
+              if (!m || !*m)
+                      ohshite("BUG in dpkg: merge command was empty but"
+                              "mergefiles() was called anyway.");
+
+              old_escaped = quotemeta( old );
+              merged_escaped = quotemeta( merged );
+              new_escaped = quotemeta( new );
+              sprintf(cmdbuf, "%.250s -o %.250s %.250s %.250s",
+                      m, merged_escaped, old_escaped, new_escaped);
+              free(new_escaped);
+              free(merged_escaped);
+              free(old_escaped);
+
+              execlp(s,s,"-c", cmdbuf, NULL);
+              ohshite(_("failed to run merge command (%.250s)"), cmdbuf);
+      }
+
+      /* prevent dpkg from terminating even if the child process is aborted */
+      newintac.sa_handler = SIG_IGN;
+      sigemptyset (&newintac.sa_mask);
+      newintac.sa_flags = 0;
+      sigaction (SIGINT, &newintac, &oldintac);
+
+      /* Parent process */
+      while (((r=waitpid(pid,&status,0))==-1) && (errno==EINTR))
+              ;
+
+      sigaction (SIGINT, &oldintac, NULL);
+
+      if (r!=pid) {
+              onerr_abort++;
+              ohshite(_("wait for shell failed"));
+      }
+
+      /* replace new conffile if merge command was succesful */
+      if (status==0 && stat(merged, &st) == 0 && (S_ISREG(st.st_mode)) && st.st_size) {
+              copyfileperm(old, merged);
+              if ((unlink(new) && errno != ENOENT) || (rename(merged,new))) {
+                      fprintf(stderr, _(" Merge failed: unable to write output file "
+                              "`%.250s' over '%.250s': %s"),
+                              merged, new, strerror(errno));
+                      return 0;
+              }
+              return 1;
+      }
+
+      unlink(merged); /* don't worry if this fails, the file may not even exist */
+      return 0;
+}
