Sisyphus repository
Last update: 22 august 2014 | SRPMs: 15030 | Visits: 5631723
en ru br
ALT Linux repos
S:4.64L-alt8.1
5.0: 4.64L-alt5.1
4.1: 4.64L-alt5
4.0: 4.64L-alt4.1
3.0: 4.58L-alt4
+backports:4.64L-alt0.M30.4

Group :: Networking/Mail
RPM: pine

 Main   Changelog   Spec   Patches   Sources   Download   Gear   Bugs and FR  Repocop 

Patch: pine-4.58L-alt2-0.4.1.diff
Download


As of pine-4.44L-alt4-0.3.0.diff, 
this path should be applied after the patch that
substitutes -lncurses with -ltinfo.
19 Oct 2002, imz@altlinux.ru
--- pine4.55/pine/filter.c.Lev	2003-05-10 13:34:47 +0400
+++ pine4.55/pine/filter.c	2003-05-10 13:34:49 +0400
@@ -65,7 +65,7 @@
 
 
 #include "headers.h"
-
+#include <pure_recode.h>
 
 /*
  * Internal prototypes
@@ -7490,3 +7490,56 @@
 
     fflush(stdout);
 }
+
+/*
+ * The recoding filter
+ * 
+ * We use our intelligent chained converter here.
+ */
+
+#include <chains.h>
+
+void
+gf_recode(f, flg)
+    FILTER_S *f;
+    int       flg;
+{
+  MultipleConverter * const mc = (MultipleConverter *)f->line; 
+  
+  unsigned char c;
+  struct CharBuffer * outbuf = buffer_createEmpty();
+
+    GF_INIT(f, f->next);
+
+    if(flg == GF_DATA) {
+		
+		while( GF_GETC(f, c) ) {
+			multiple_conv_feedc(mc, c, outbuf);
+			while (! buffer_isEmpty(outbuf)) {
+				c = buffer_getc(outbuf);
+   				GF_PUTC(f->next, c);
+			}
+		}
+		buffer_destroy(outbuf);
+
+		GF_END(f, f->next);
+    }
+    else if(flg == GF_EOD) {
+		multiple_conv_close(mc, outbuf);
+		while (! buffer_isEmpty(outbuf)) {
+		  c = buffer_getc(outbuf);
+		  GF_PUTC(f->next, c);
+		}
+		buffer_destroy(outbuf);
+		
+		f->line = NULL;
+		
+		GF_FLUSH(f->next);
+		(*f->next->f)(f->next, GF_EOD);
+    }
+    else if(flg == GF_RESET) {
+		dprint(9, (debugfile, "-- gf_reset recode\n"));
+		f->line = 
+		  (char*) multiple_conv_open(((const struct Chain *)f->opt)->first);
+    }
+}
--- pine4.55/pine/mailpart.c.Lev	2003-03-11 21:51:00 +0300
+++ pine4.55/pine/mailpart.c	2003-05-10 13:34:49 +0400
@@ -46,7 +46,7 @@
   ====*/
 
 #include "headers.h"
-
+#include "recodeg.h"
 
 /*
  * Information used to paint and maintain a line on the attachment
@@ -208,7 +208,19 @@
 	{"%", "Print", MC_PRINTMSG,1,{'%'}, KS_PRINT},
 	NULL_MENU,
 	REPLY_MENU,
-	FORWARD_MENU};
+	FORWARD_MENU,
+        HELP_MENU,
+        OTHER_MENU,
+        {"^R", "Recode", {MC_RECODE, 1, {ctrl('r')}}, KS_NONE},
+        NULL_MENU,
+        NULL_MENU,
+        NULL_MENU,
+        NULL_MENU,
+        NULL_MENU,
+        NULL_MENU,
+        NULL_MENU,
+        NULL_MENU,
+        NULL_MENU};
 INST_KEY_MENU(att_view_keymenu, att_view_keys);
 #define	ATV_BACK_KEY	 2
 #define	ATV_VIEW_HILITE	 3
@@ -234,6 +246,13 @@
 /* used to keep track of detached MIME segments total length */
 static long	save_att_length;
 
+/* Lev: very GW-BASIC way to patch Pine. The program exits from ATTACHED
+ * TEXT screen if I want to change the viewing text (after recoding)
+ * in the way, used in MESSAGE TEXT screen. So I allow it to exit
+ * from ATTACHED TEXT to the ATTACHMENT INDEX, and then, if this
+ * flag is set, it view attachment again... ;-( */
+static int      view_att_again = 0;
+
 /*
  * Internal Prototypes
  */
@@ -594,12 +613,19 @@
 		       ps_global->ttyo->screen_rows -(FOOTER_ROWS(ps_global)+1),
 		       ps_global->ttyo->screen_cols);
 #endif
-	ch = read_command();
+	if(!view_att_again)
+	    ch = read_command();
+
 #ifdef	MOUSE
 	clear_mfunc(mouse_in_content);
 #endif
 
-	cmd = menu_command(ch, &att_index_keymenu);
+	if(view_att_again) {
+	    cmd = MC_VIEW_ATCH;
+	    view_att_again = 0;
+	}
+	else
+	    cmd = menu_command(ch, &att_index_keymenu);
 
 	if(km_popped)
 	  switch(cmd){
@@ -2676,6 +2702,11 @@
 	ps_global->mangled_footer = 1;
 	break;
 
+      case MC_RECODE :
+        if(rv = cmd_recode(ps_global))
+	    view_att_again = 1;
+	break;	
+
       default:
 	panic("Unexpected command case");
 	break;
--- pine4.55/pine/makefile.lnx.Lev	2003-05-10 13:34:47 +0400
+++ pine4.55/pine/makefile.lnx	2003-05-10 13:34:49 +0400
@@ -64,8 +64,10 @@
 LOCLIBS=     $(PICODIR)/libpico.a $(CCLIENTDIR)/c-client.a
+LOCLIBS+=     my_util/libmy_util.a pure_recode/pure_recode.a
 LIBS=        $(LOCLIBS) $(LDAPLIBS) $(STDLIBS) \
              `cat $(CCLIENTDIR)/LDFLAGS`
 
 STDCFLAGS=   -DLNX -DSYSTYPE=\"LNX\" -DMOUSE
+STDCFLAGS+=   -Imy_util -Ipure_recode -DRECODEG_PINE
 CFLAGS=      $(OPTIMIZE) $(PROFILE) $(DEBUG) $(EXTRACFLAGS) $(LDAPCFLAGS) \
 	     $(STDCFLAGS)
 
@@ -73,7 +75,7 @@
 	folder.o help.o helptext.o imap.o init.o mailcap.o mailcmd.o \
 	mailindx.o mailpart.o mailview.o newmail.o other.o pine.o \
 	reply.o screen.o send.o signals.o status.o strings.o takeaddr.o \
-	os.o
+	os.o recodeg.o
 
 HFILES=	headers.h os.h pine.h context.h helptext.h \
 	$(PICODIR)/headers.h $(PICODIR)/estruct.h \
@@ -114,6 +116,7 @@
 addrbook.o adrbkcmd.o adrbklib.o bldaddr.o takeaddr.o:	adrbklib.h
 context.o:						$(CCLIENTDIR)/misc.h
 send.o:							$(CCLIENTDIR)/smtp.h
+recodeg.o mailview.o mailcmd.o:			recodeg.h
 #$(LDAPOFILES):						$(LDAPLIBS)
 
 helptext.c:	pine.hlp
@@ -135,3 +138,9 @@
 		osdep/sendmail osdep/execview \
 		osdep/postreap.wtp osdep/os-lnx.ic
 		cd osdep; $(MAKE) includer os-lnx.c; cd ..
+
+my_util/libmy_util.a pure_recode/pure_recode.a: .FORCE
+	(cd "$$(dirname "$@")"; $(MAKE) "$$(basename "$@")"; )
+
+.FORCE:
+
--- pine4.55/pine/pine.h.Lev	2003-05-10 13:34:49 +0400
+++ pine4.55/pine/pine.h	2003-05-10 13:34:49 +0400
@@ -1057,6 +1057,13 @@
 	F_SAVE_WONT_DELETE,
 	F_SAVE_ADVANCES,
 	F_UNSELECT_WONT_ADVANCE,
+	F_FSAVE_NO_WRAP,
+	F_FSAVE_STOP_RECODE,
+	F_WRAP_FOR_REPLY,
+	F_RECODE_FOR_REPLY,
+	F_DONT_ENCODE,
+	F_DONT_ENCODE_TXTATTS,
+	F_ADD_X_RECODE,
 	F_FORCE_LOW_SPEED,
 	F_ALT_ED_NOW,
 	F_SHOW_DELAY_CUE,
@@ -3168,6 +3175,7 @@
     unsigned	 thread_index_style:3;
 
     unsigned     full_header:1;         /* display full headers */
+    unsigned     recode_header:1;         /* recode headers */
     unsigned     orig_use_fkeys:1;
     unsigned     try_to_create:1;	/* Save should try mail_create */
     unsigned     low_speed:1;		/* various opt's 4 low connect speed */
--- pine4.55/pine/reply.c.Lev	2003-03-26 21:18:16 +0300
+++ pine4.55/pine/reply.c	2003-05-10 13:34:49 +0400
@@ -61,6 +61,7 @@
 
 
 #include "headers.h"
+#include "recodeg.h"
 
 
 
@@ -587,8 +588,9 @@
 	if(orig_body){
 	    char *charset;
 
-	    charset = rfc2231_get_param(orig_body->parameter,
-					"charset", NULL, NULL);
+	    charset = 
+	      recodeg_validcharset(rfc2231_get_param(orig_body->parameter,
+						     "charset", NULL, NULL));
 	    if(charset && strucmp(charset, "us-ascii") != 0){
 		/*
 		 * There is a non-ascii charset, is there conversion happening?
@@ -1483,6 +1485,8 @@
     return(rlist);
 }
 
+#include <stdlib.h>
+#include <string.h>
 
 /*----------------------------------------------------------------------
     Format and return subject suitable for the reply command
@@ -1525,6 +1529,15 @@
       sprintf(buf, "Re: %.200s", (subject && *subject) ? subject : "your mail");
 
     fs_give((void **) &tmp);
+    if(ps_global->recode_header && recodeg_used()) {
+	  tmp = multiple_conv_str(recodeg_rules(), buf);
+#define BUF_SIZE (l+5)
+	  strncpy(buf, tmp, BUF_SIZE - 1);
+	  buf[BUF_SIZE - 1] = '\0';
+#undef  BUF_SIZE
+	  free(tmp);
+	 }
+
     return(buf);
 }
 
@@ -3850,8 +3863,9 @@
     if(ret != 'y' && totalmsgs == 1L && orig_body){
 	char *charset;
 
-	charset = rfc2231_get_param(orig_body->parameter,
-				    "charset", NULL, NULL);
+	charset = 
+	  recodeg_validcharset(rfc2231_get_param(orig_body->parameter,
+						 "charset", NULL, NULL));
 	if(charset && strucmp(charset, "us-ascii") != 0){
 	    /*
 	     * There is a non-ascii charset, is there conversion happening?
@@ -4625,9 +4639,12 @@
     char       *prefix;
 {
     int		i, we_cancel = 0, dashdata;
-    FILTLIST_S  filters[7];
+    FILTLIST_S  filters[9];
     long	len;
     char       *err, *charset;
+    int         width = ps_global->composer_fillcol -
+                            (prefix ? strlen(prefix) : 0);
+
 #if	defined(DOS) && !defined(WIN32)
     char     *tmpfile_name = NULL;
 #endif
@@ -4752,13 +4769,28 @@
 	else if(strucmp(body->subtype,"html") == 0){
 	    filters[i].filter = gf_html2plain;
 	    filters[i++].data = gf_html2plain_opt(NULL,
-						  ps_global->ttyo->screen_cols,
+						  width, 
 						  NULL,
 						  GFHP_STRIPPED);
 	}
     }
 
+    /* We put the recoding filter as early as possible -- so that
+		other filters don't spoil the encoded text;
+		
+	  We put it outside the check for (prefix) -- since it should be 
+		done for replies as well as for forwards.
+	*/
+	if(F_ON(F_RECODE_FOR_REPLY, ps_global) && recodeg_used()) {
+      filters[i].filter = gf_recode;
+      filters[i++].data = recodeg_rules();
+    }
+
     if(prefix){
+      	if(F_ON(F_WRAP_FOR_REPLY, ps_global)) {
+            filters[i].filter = gf_wrap;
+            filters[i++].data = gf_wrap_filter_opt(width, width, 0, 0);
+        }
 	if(F_ON(F_ENABLE_SIGDASHES, ps_global) ||
 	   F_ON(F_ENABLE_STRIP_SIGDASHES, ps_global)){
 	    dashdata = 0;
--- pine4.55/pine/strings.c.Lev	2003-04-03 04:13:32 +0400
+++ pine4.55/pine/strings.c	2003-05-10 13:34:49 +0400
@@ -2919,6 +2919,7 @@
 unsigned char *rfc1522_encoded_word PROTO((unsigned char *, int, char *));
 
 
+#include "recodeg.h"
 /*
  * rfc1522_decode - decode the given source string ala RFC 2047 (nee 1522),
  *		    IF NECESSARY, into the given destination buffer.
@@ -2942,6 +2943,8 @@
     unsigned long  l;
     int		   i;
     int            translate_2022_jp = 0;
+    struct Chain * recode_rules = NULL;
+    int recode_rules_mustFree = 0;
 
     *d = '\0';					/* init destination */
     if(charset)
@@ -3016,6 +3019,43 @@
 		}
 	    }
 
+	    /* Recoding is always done; 
+	       no matter what the mode is (auto/manual).
+	       This is due to the recoded headers are cached,
+	       and it is better to have them in a unified encoding.
+	    */
+#if 0
+	    if ( recodeg_auto() ) {
+#endif
+	      if (ps_global->VAR_CHAR_SET
+		  && strucmp((char *) cset, ps_global->VAR_CHAR_SET)
+		  && strucmp((char *) cset, "US-ASCII")) 
+		{
+		  recode_rules = chain_createEmpty();
+		  recode_rules_mustFree = 1;
+		  if (addRecodeRule(recode_rules, 
+				    (char *) cset, ps_global->VAR_CHAR_SET)) 
+		    {
+		      destroyRecodeRules(recode_rules);
+		      recode_rules = NULL;
+		    }
+		}
+#if 0
+	    }
+	    else if ( recodeg_used() ) {
+	      recode_rules = recodeg_rules();
+	      recode_rules_mustFree = 0;
+	    }
+#endif
+
+	    if (recode_rules) {
+	      const char * const info = infoOnRecodeRules(recode_rules);
+	      dprint(5, (debugfile, "RFC1522_decode: recoding %s\n",
+			   info));
+	      free((char*)info);
+	    }
+
+	
 	    /* based on encoding, write the encoded text to output buffer */
 	    switch(*enc){
 	      case 'Q' :			/* 'Q' encoding */
@@ -3134,6 +3174,21 @@
 	    fs_give((void **) &trans);
 	}
     }
+    else if (recode_rules) {
+	char *trans;
+
+	/*
+	 * We want to do the recoding in place in the string, but to do
+	 * that first we get an allocated copy of the recoded string and then
+	 * we put it back into rv.
+	 */
+	trans = multiple_conv_str(recode_rules, rv);
+	if(trans){
+	    istrncpy(rv, trans, len);
+	    rv[len - 1] = '\0';
+	    free(trans);
+	}
+    }
     else if(cs){
 	if(rv && F_OFF(F_DISABLE_CHARSET_CONVERSIONS, ps_global)
 	   && ps_global->VAR_CHAR_SET
@@ -3154,6 +3209,10 @@
 	}
     }
 
+    if (recode_rules && recode_rules_mustFree) {
+      destroyRecodeRules(recode_rules);
+      recode_rules = NULL;
+    }
     if(cs)
       fs_give((void **) &cs);
 
--- pine4.55/pine/init.c.Lev	2003-05-10 13:34:48 +0400
+++ pine4.55/pine/init.c	2003-05-10 13:34:49 +0400
@@ -2458,6 +2458,10 @@
 	 F_INCLUDE_HEADER, h_config_include_header, PREF_RPLY},
 	{"include-text-in-reply",
 	 F_AUTO_INCLUDE_IN_REPLY, h_config_auto_include_reply, PREF_RPLY},
+	{"wrap-text-for-reply",
+	 F_WRAP_FOR_REPLY, h_config_wrap_for_reply, PREF_RPLY},
+	{"recode-text-for-reply",
+	 F_RECODE_FOR_REPLY, h_config_recode_for_reply, PREF_RPLY},
 	{"reply-always-uses-reply-to",
 	 F_AUTO_REPLY_TO, h_config_auto_reply_to, PREF_RPLY},
 	{"signature-at-bottom",
@@ -2714,6 +2718,10 @@
 	 F_QUOTE_ALL_FROMS, h_config_quote_all_froms, PREF_MISC},
 	{"scramble-message-id",
 	 F_ROT13_MESSAGE_ID, h_config_scramble_message_id, PREF_MISC},
+	{"fmt-save-will-not-wrap",
+	 F_FSAVE_NO_WRAP, h_config_fsave_no_wrap, PREF_MISC},
+	{"stop-recoding-after-fmt-save",
+	 F_FSAVE_STOP_RECODE, h_config_fsave_stop_recode, PREF_MISC},
 	{"select-without-confirm",
 	 F_SELECT_WO_CONFIRM, h_config_select_wo_confirm, PREF_MISC},
 	{"show-cursor",
@@ -2738,6 +2746,8 @@
 	 F_SUSPEND_SPAWNS, h_config_suspend_spawns, PREF_OS_SPWN},
 	{"use-function-keys",
 	 F_USE_FK, h_config_use_fk, PREF_OS_USFK},
+	{"add-x-recoded-line",
+	 F_ADD_X_RECODE, h_config_add_x_recode, PREF_MISC},
 
 /* Hidden Features */
 	{"old-growth",
--- pine4.55/pine/pine.hlp.Lev	2003-05-10 13:34:49 +0400
+++ pine4.55/pine/pine.hlp	2003-05-10 13:34:50 +0400
@@ -431,6 +431,110 @@
 <CENTER><SAMP><A HREF="http://www.washington.edu/pine/changes.html">http://www.washington.edu/pine/changes.html</A></SAMP></CENTER>
 <P>
 
+<a name="Lev"><h3>New features in the L-extension</h3>
+
+This extension of Pine was originally developed 
+by Lev Levitin &lt;lev@mccme.ru&gt; at Moscow State Fifty-Seventh School
+&lt;http://www.sch57.msk.ru&gt;
+on the base of Pine 4.21,
+and the extended program was called 4.21L. Further development
+of this extension was overtaken by Ivan Zakharyaschev
+&lt;imz@altlinux.ru&gt;, ALT Linux Team &lt;http://www.altlinux.ru&gt;.
+<p>The recoding facilities are NOT intended for use with enabled <A HREF="h_config_disable_cset_conv">charset conversion</A> (and probably <A HREF="h_config_disable_2022_jp_conv">Japanese charset conversion</A>). So if you want to use recoding, add <A HREF="h_config_disable_cset_conv">disable-charset-conversions</A> and <A HREF="h_config_disable_2022_jp_conv">disable-2022-jp-conversions</A> to your configuration.
+<p>Here is the track of new features/changes.
+
+<h4>L-0.4.0 (based on 4.53, May 2003)</h4>
+
+<ul>
+
+  <li> fix Formatted Save ($) command dialog;
+  <li> fix crash when replying to a recoded message;
+  <li> fix crash when working with formatted saved msgs with recoded headers;
+  <li> add support for smart autorecoding of rfc1522-strings (used in headers);
+  <li> if formatted-save-stop-recode is on, bring Pine to the auto-recode mode 
+    after a formatted save operation ($);
+  <li> introduce "brute recoding of headers" mode (^R H) on top of the 
+    normal "smart" recoding; it replaces the obsolete 
+    "recode-header" configuration option present in previous releases;
+  <li> change internals of the Pine-filter-recoding interaction:
+    store the recoding pipe per filter;
+  <li> other enhancements in the internals.
+
+</ul>
+
+<h4>L-0.3.0 (based on 4.42)</h4>
+
+<ul>
+
+  <li>The recoding engine rewritten by Ivan Zakharyaschev 
+	&lt;imz@altlinux.ru&gt; in order to support multibyte
+	character sets; such charsets added to the list of available:
+	UTF-8, UTF-7, UCS-4;
+
+  <li>auto-recoding is ON by default; the "charset editorial" tells a 
+	user whether autorecoding is performed on the viewed message;
+  
+  <li>recoding of forwarded messages fixed.
+
+</ul>
+
+<h4>L-0.2.2 (based on 4.30)</h4>
+
+<ul>
+
+  <li>A system of charset naming introduced to recode. Now the user sees short 
+  names of them: they should not be regarded as conforming to any 
+  standard. The charsets in the recoding rules internals are now strictly 
+  the same as in the rest of PINE (sounds like IANA); they are transformed 
+  to charset names known by the system straight before recoding. So the 
+  names really used are long ones like "windows-1251", "paratype-154" 
+  and not "cp1251" (though this name is shown in the choice menu).
+
+</ul>
+
+<h4>L-0.2.1 (based on 4.30)</h4>
+
+<ul>
+  <li> Automatic recoding now works with messages where the charset is 
+  stated as "windows-1251". (Other "windows-*" should be understood 
+  correctly as well.)
+  
+  <li> Support for Asian Cyrillic encoding known as PT154 
+  (or paratype-154 in documents) added.
+  
+  <li> 7-bit Cyrillic (KOI7) messages can be handled by the recoding system. 
+  The current implementation is not perfect in two aspects:
+  <ol>
+	<li> the value of the header "Content-Type" of messages saved in KOI7 
+	doesn't correspond with the reality (it says it is 8-bit);
+	<li> messages where words made up of either Cyrillic or Latin letters are 
+	both present are not decoded in a "reader-friendly" way.
+  </ol>
+</ul>
+
+<h4>L-0.2 (based on 4.21)</h4>
+The extension provides the facility of
+recoding a message text and some minor features.
+Those who use cyrillic letters may face a sort of problem:
+there are four different cyrillic character sets, and your local set
+may not coincide with the charset of the received message.
+In this case the solution is <A HREF="h_view_recode">the recoding</A>
+of the text. Currently only 5 cyrillic character sets are supported.
+
+<P>
+The automatic recoding is supported as well as manual. The former
+works properly only if the message header contains correct information
+about the source charset, while the latter can help you if automatic
+recoding fails and even if the message was incorrectly recoded by
+mail servers it has passed throw. Unfortunately, there is no clever
+routines to help you in such cases.
+
+<P>
+Some other changes from the version 4.21 are <A HREF="h_common_save">the
+formatted save</A> and <A HREF="h_common_reply">formatted reply
+</A>, which allows to apply some filtering (line wrapping, recoding,
+etc.) before saving mail into folders or replying.
+
 <HR WIDTH="75%"><P>
 
 <H2>Getting Help</H2>
@@ -2817,6 +2920,7 @@
 <li><a href="h_news">RELEASE NOTES for Pine</a>
 <li><a href="h_role_select">ROLES SCREEN</a>
 <li><a href="h_compose_readfile">Read File Command</a>
+<li><a href="h_view_recode">Recode Command</a>
 <li><a href="h_main_release_notes">Release Notes Command</a>
 <li><a href="h_common_reply">Reply and Forward Commands</a>
 <li><a href="h_compose_richhdr">Rich Header Command</a>
@@ -2848,7 +2952,7 @@
 <li><a href="h_rules_incols">SETUP INDEX COLORS SCREEN</a>
 <li><a href="h_rules_filter">SETUP FILTERING SCREEN</a>
 <li><a href="h_rules_score">SETUP SCORING SCREEN</a>
-<li><a href="h_common_save">Save and Export Commands</a>
+<li><a href="h_common_save">Save, Formatted Save and Export Commands</a>
 <li><a href="h_index_cmd_select">Selecting: Select and WhereIs/Select</a>
 <li><a href="h_compose_send">Send Command</a>
 <li><a href="h_main_setup">Setup Command</a>
@@ -3758,6 +3862,7 @@
 &nbsp;T&nbsp;&nbsp;&nbsp;<A HREF="h_common_take">Take&nbsp;Address</A>&nbsp;into&nbsp;Address&nbsp;Book&nbsp;&nbsp;&nbsp;^B&nbsp;&nbsp;Select&nbsp;previous&nbsp;<A HREF="h_view_cmd_hilite">hilited</A>&nbsp;item<BR>
 &nbsp;%&nbsp;&nbsp;&nbsp;<A HREF="h_common_print">Print</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;<A HREF="h_common_flag">Flag</A>&nbsp;message<BR>
 &nbsp;W&nbsp;&nbsp;&nbsp;<A HREF="h_view_cmd_whereis">Whereis</A>:&nbsp;search&nbsp;for&nbsp;text&nbsp;in&nbsp;msg&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;<A HREF="h_common_pipe">Pipe</A>&nbsp;to&nbsp;a&nbsp;Unix&nbsp;command<BR>
+&nbsp;^R&nbsp;&nbsp;<A HREF="h_view_recode">Recode</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$&nbsp;&nbsp;<A HREF="h_common_save">Formatted&nbsp;copy&nbsp;save<A><BR>
 <BR>
 Navigating&nbsp;the&nbsp;List&nbsp;of&nbsp;Messages&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Other&nbsp;Commands<BR>
 -------------------------------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;----------------------------<BR>
@@ -3824,6 +3929,12 @@
 display ISO-8859-1.  Displays for other characters sets are less common.
 <P>
 
+Sometimes there are different character sets for one language, and
+the incomming mail is in one of them, while your terminal correctly
+displays another. In this case try <A HREF="h_view_recode">recode</A>
+command.
+<P>
+
 Pine usually suppresses display of control characters in order to avoid
 characters which may change terminal setup parameters.
 If this is a problem for you, the
@@ -4359,6 +4470,111 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+======= h_view_recode =======
+<HTML>
+<HEAD>
+<TITLE>Recode Command</TITLE>
+</HEAD>
+<BODY>
+<H1>Recode Command</H1>
+
+For some languages there are several character sets, and you can
+face a problem, that some message you have received is written in
+the character set, different from your local one, but the language is
+the same, so there are the same letters encoded in two various ways.
+The solution of the problem may be the recoding of message.
+<p>The recoding facilities were brought to Pine by external developpers and so they may conflict with some internal featrures: they are NOT intended for use with enabled <A HREF="h_config_disable_cset_conv">charset conversion</A> (and probably <A HREF="h_config_disable_2022_jp_conv">Japanese charset conversion</A>). So if you want to use recoding, add <A HREF="h_config_disable_cset_conv">disable-charset-conversions</A> and <A HREF="h_config_disable_2022_jp_conv">disable-2022-jp-conversions</A> to your configuration. (The interaction of recoding and these conversions simply has not been tested.)
+<P>
+
+The Recode (^R) command allows manual recoding as well as the
+automatic one. After pressing (^R) sequence the recoding menu comes, where
+the user is able to turn on/off automatic recoding or to manage
+the recoding process manually. One is also able to switch recoding
+of message headers on or off there.
+<P>
+
+Recoding is based on the so called &quot;recoding rules&quot; -
+the pairs of
+character set names. A chain of them defines the recoding process.
+Usually, you only need a single recoding rule, but sometimes,
+if you have to repair the wrong recoding due to some mail agent, you
+may need more than one rule in the chain. When recoding menu is shown, the
+currently used chain of recoding rules can be watched in the top
+line of menu. It is enclosed by square brackets; initally it is
+empty: &quot;[]&quot; you can append the rule to the end of
+chain (by pressing &quot;+&quot;), remove last rule in the chain
+(&quot;-&quot;) or completely clear the whole chain (&quot;D&quot;).
+<P>
+When manually adding a recoding rule, you have to select
+a pair of character sets using <A HREF="h_charset_menu">the charset
+menu</A>.
+<P>
+
+The automatic recoding (^R A) tries to find out the character set
+information from the message header and convert
+message from that one to the terminal character set specified in
+Pine configuration. It cleans up all existing recode rules and
+the two character sets constitute the new single rule: 
+message_charset-&gt;local_charset. 
+When you move on to another message, Pine applies the same recoding conversion to it. To turn the automatic recoding off,
+type (^R A) again, or execute any of the manual recoding commands. This
+stops the automatic recoding mode: no new rules are built automatically,
+but the rule already built automatically remain, 
+until you rearrange them.
+<P>
+
+Normally, message headers do not include 8-bit data. Texts in various
+languages are encoded in a more complex way when they are in a header,
+and these encodings are dealt in an automatic mode by Pine. But you can
+apply the same recoding conversion you arranged for the message you
+view to the header; on top of the automatic decoding mentioned
+above. This operation can be useful in some rare cases with bad 8-bit
+headers. To go into the mode for recoding headers by typing (^R H),
+and go back by the same key-sequence. The mode is active for any
+viewed message.
+
+Several different Pine commands honor the recode mode -- it affects how
+messages are displayed, how they are printed and how they are exported.
+<!--chtml if pinemode="os_windows"-->
+<!--chtml else--> 
+The pipe command is also affected.
+<!--chtml endif-->
+<P>
+
+<UL>   
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
+======= h_charset_menu =======
+<HTML>
+<HEAD>
+<TITLE>Character set Menu</TITLE>
+</HEAD>
+<BODY>
+<H1>Character set Menu</H1>
+
+Character set menu is used to
+select charsets for manual <A HREF="h_view_recode">recoding</A> and
+to select a charset for the new message when <A HREF="h_common_save">
+saving a formatted copy of message</A>
+<P>
+Currently only several precompiled charsets
+are available plus the default one.
+These are mostly all cyrillic ones:
+KOI8-R, KOI8-U (Ukranian version), KOI-7 (7 bit), PT154 (Asian version),
+CP866, CP1251 and ISO-8859-5 -- as well as some multibyte Unicode charsets. Your local charset goes as the default
+when selecting for recoding, and when you are invoking the formatted save
+command the default charset is automaticaly fetched by Pine.
+<P>
+The default charset may be one of five counted about as well as may not.
+<P>
+
+<P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
 ======= h_index_cmd_expunge =======
 <HTML>
 <HEAD>
@@ -4828,13 +5043,14 @@
 <H1>Save and Export Commands</H1>
 
 Save
-(<!--chtml if pinemode="function_key"-->F11<!--chtml else-->S<!--chtml endif-->)
-and Export
+(<!--chtml if pinemode="function_key"-->F11<!--chtml else-->S<!--chtml endif-->),
+Export
 (<!--chtml if pinemode="function_key"-->F12<!--chtml else-->E<!--chtml endif-->)
-are the two alternatives Pine gives you to keep a copy of the message
+and Formatted Save ($) (within <A HREF="h_mail_view">a message text screen</A>)
+are the three alternatives Pine gives you to keep a copy of the message
 you are reading. If you want to keep the message within Pine's email
-world, use &quot;Save&quot;; if you want to use the message in another
-program, use &quot;Export&quot;.
+world, use one of &quot;Save&quot; commands; if you want to use the
+message in another program, use &quot;Export&quot;.
 <P>
 
 When you Save a message, it is put into an existing folder or into a new
@@ -4850,6 +5066,25 @@
 feature list settings.
 <P>
 
+Formatted save command builds a formatted copy of a message, e.g.
+create a new message which text is the same, as what you view.
+The line wrapping and recoding are applied to the message text.
+The result is been saved into the current folder.
+Note, that this command does not change any attachments, even text ones.
+The result is been saved into the current folder.
+Note, that this command does not change any attachments, even text ones.
+<P>
+
+This command depends on feature
+<A HREF="h_config_save_wont_delete">&quot;save-will-not-delete&quot;</A>
+as &quot;Save&quot; command does. It also depends on features
+<A HREF="h_config_fsave_no_wrap">&quot;fmt-save-will-not-wrap&quot;</A>,
+<A HREF="h_config_fsave_stop_recode">
+&quot;stop-recoding-after-fmt-save&quot;</A>,
+<A HREF="h_config_add_x_recode">&quot;add-x-recoded-line&quot;</A>,
+and on whether the mode for recoding headers is on.
+
+<P>
 When you use Export, the message is placed in a plain text file in your
 home directory 
 <!--chtml if pinemode="running"-->
@@ -10025,6 +10260,12 @@
 (If you have any <A HREF="h_config_display_filters">Display-Filters</A>
 defined, they may affect the contents of the exported file.)
 
+<DT>Recode</DT>
+<DD>If you watch some unreadable text in the attachment, try
+to recover with <A HREF="h_view_recode">. It can help you
+when the problem is wrong character set of attachment, while
+it's in the language, that your terminal supports.
+
 <DT>Pipe</DT>
 <DD>Pipe the attachment contents into a UNIX command (if enabled)
 
@@ -24758,6 +24999,55 @@
 &lt;End of help on this topic&gt;
 </BODY>
 </HTML>
+====== h_config_wrap_for_reply =====
+         FEATURE: wrap-text-for-reply
+
+This feature controls an aspect of Pine's Reply command. If set, and the
+text of the message, which you reply to, is being passed throw line
+wrapping filter before inserting prefixes ("> ", e.g.) to each line.
+
+<End of help on this topic>
+====== h_config_recode_for_reply =====
+         FEATURE: recode-text-for-reply
+
+This feature controls an aspect of Pine's Reply command. If set, and the
+text of the message, which you reply to is being passed throw recode filter.
+
+<End of help on this topic>
+====== h_config_fsave_no_wrap =====
+          FEATURE: fmt-save-will-not-wrap
+
+This feature controls one aspect of the Formatted Save command.
+If set, Formatted Save will not apply line wrapping filter to
+the text of message.
+
+<End of help on this topic>
+====== h_config_fsave_stop_recode =====
+          FEATURE: stop-recoding-after-fmt-save
+
+This feature controls the behaviour of the Formatted Save command.
+Than a manual recoding is used and the formatted message is saved,
+if you jump to it after recoding, you view text, which is recoded
+twice. There are two ways to prevent this: not to jump to the
+formatted copy, or turn off the recoding.
+
+If this option is set, the second way is selected. Overwise, user
+is prompted, does he like to jump to the formatted copy, or not.
+
+<End of help on this topic>
+====== h_config_add_x_recode =====
+        FEATURE: add-x-recoded-line
+
+If this feature is set, when doing the formatted save and
+the recoding is working, line of format:
+
+  X-Recoded: [enc1->enc2 ... enc(N-1)->encN] by someone@somewhere.net
+ 
+is been appended to the header of message. It contains the
+complete information about the recoding, been applied to the
+text.
+
+<End of help on this topic>
 ====== h_config_quell_folder_internal_msg ======
 <HTML>
 <HEAD>
--- pine4.55/pine/mailview.c.Lev	2003-03-19 03:10:30 +0300
+++ pine4.55/pine/mailview.c	2003-05-10 13:34:50 +0400
@@ -47,6 +47,7 @@
 
 
 #include "headers.h"
+#include "recodeg.h"
 
 
 /*----------------------------------------------------------------------
@@ -152,11 +153,16 @@
 
 #define TYPICAL_BIG_MESSAGE_LINES	200
 
-#define	CHARSET_DISCLAIMER_1	\
-	"The following text is in the \"%.40s\" character set.\015\012Your "
-#define	CHARSET_DISCLAIMER_2	"display is set"
-#define	CHARSET_DISCLAIMER_3	\
-       " for the \"%.40s\" character set. \015\012Some %.40scharacters may be displayed incorrectly."
+#define AUTO_RECODE_USED ( recodeg_auto() && recodeg_used() )
+#define	CHARSET_DISCLAIMER_1	( AUTO_RECODE_USED \
+	? "Auto-recoded from the \"%.40s\" character set\015\012" \
+	: "The following text is in the \"%.40s\" character set.\015\012Your " \
+)
+#define	CHARSET_DISCLAIMER_2	( AUTO_RECODE_USED ? "to" : "display is set" )
+#define	CHARSET_DISCLAIMER_3	( AUTO_RECODE_USED \
+	? " \"%.40s\" (which your display is set for). \015\012Press ^R for switching to manual mode." \
+	: " for the \"%.40s\" character set. \015\012Some characters may be displayed incorrectly." \
+)
 #define ENCODING_DISCLAIMER      \
         "The following text contains the unknown encoding type \"%.20s\". \015\012Some or all of the text may be displayed incorrectly."
 
@@ -207,8 +213,8 @@
 
 	HELP_MENU,
 	OTHER_MENU,
-	NULL_MENU,
-	NULL_MENU,
+        {"^R", "Recode", {MC_RECODE, 1, {ctrl('r')}}, KS_NONE},
+        {"$", "FmtdSave", {MC_FMTSAVE, 1, {'$'}}, KS_NONE},
 	RCOMPOSE_MENU,
 	NULL_MENU,
 	NULL_MENU,
@@ -233,7 +239,7 @@
 	NULL_MENU,
 	{"E","Exit Viewer",{MC_EXIT,1,{'e'}},KS_EXITMODE},
 	NULL_MENU,
-	NULL_MENU,
+        {"^R", "Recode", {MC_RECODE, 1, {ctrl('r')}}, KS_NONE},
 	NULL_MENU,
 	PREVPAGE_MENU,
 	NEXTPAGE_MENU,
@@ -1076,6 +1082,9 @@
   Mapping table use to neatly display charset parameters
  ----*/
 
+/* The first field should be a name of a document encoding like
+  windows-1251. Now not all of them are so; some are system encoding 
+  names. Should be fixed. Ivan Z. */
 static struct set_names {
     char *rfcname,
 	 *humanname;
@@ -1109,7 +1118,11 @@
     {"ISO-2022-KR",		"Latin & Korean"},
     {"UTF-7",			"7-bit encoded Unicode"},
     {"UTF-8",			"Internet-standard Unicode"},
-    {"ISO-2022-JP-2",		"Multilingual"},
+    {"ISO-2022-JP-2",	"Multilingual"},
+    {"CP886",			"Latin & Cyrillic"},
+    {"WINDOWS-1251",	"Latin & Cyrillic"},
+    {"PARATYPE-154",	"Asian Cyrillic"},
+    {"KOI-7",			"7-bit Cyrillic"},
     {NULL,			NULL}
 };
 
@@ -1447,6 +1460,11 @@
       q_status_message(SM_INFO, 0, 3,
 		       "Full header mode ON.  All header text being included");
 
+    if(flgs & FM_NEW_MESS) {
+	zero_atmts(ps_global->atmts);
+	describe_mime(body, "", 1, 1, 0);
+    }
+
     HD_INIT(&h, ps_global->VAR_VIEW_HEADERS, ps_global->view_all_except,
 	    FE_DEFAULT);
     switch(format_header(ps_global->mail_stream, msgno, NULL,
@@ -1568,11 +1586,6 @@
 	return(1);
     }
 
-    if(flgs & FM_NEW_MESS) {
-	zero_atmts(ps_global->atmts);
-	describe_mime(body, "", 1, 1, 0);
-    }
-
     /*=========== Format the header into the buffer =========*/
     /*----- First do the list of parts/attachments if needed ----*/
     if((flgs & FM_DISPLAY) && ps_global->atmts[1].description){
@@ -5003,7 +5016,7 @@
     DetachErrStyle  style;
     int		    flags;
 {
-    FILTLIST_S	filters[13];
+    FILTLIST_S	filters[14];
     char       *err, *charset;
     int		filtcnt = 0, error_found = 0, column, wrapit;
     int         is_in_sig = OUT_SIG_BLOCK;
@@ -5012,6 +5025,14 @@
     wrapit = column;
 
     memset(filters, 0, sizeof(filters));
+
+    if(recodeg_auto())
+	recodeg_autosolve(att->body);
+    if(recodeg_used()) {
+        filters[filtcnt].filter = gf_recode;
+        filters[filtcnt++].data = recodeg_rules();
+    }
+
     if(F_OFF(F_DISABLE_2022_JP_CONVERSIONS, ps_global))
       filters[filtcnt++].filter = gf_2022_jp_to_euc;
 
@@ -5142,7 +5163,12 @@
      * If there's a charset specified and it's not US-ASCII, and our
      * local charset's undefined or it's not the same as the specified
      * charset, put up a warning...
+     * Lev: If user applies any recoding using ^R, we disable
+     * the wrong charset warning.
+     * Ivan: if autorecoding is active, we put a message (of another 
+     *  type) as well.
      */
+    if ( ! recodeg_used() || recodeg_auto() )
     if((!ct || ct->quality != CV_NO_TRANSLATE_NEEDED) &&
        (charset = rfc2231_get_param(att->body->parameter,"charset",NULL,NULL))){
 	int rv = TRUE;
@@ -5470,6 +5496,15 @@
 
 	if(!rv){
 	    gf_filter_init();
+
+            if(ps_global->recode_header &&
+                ps_global->atmts->description) {
+                if(recodeg_auto())
+                    recodeg_autosolve(ps_global->atmts->body);
+                if(recodeg_used())
+                    gf_link_filter(gf_recode, recodeg_rules());
+            }
+
 	    gf_link_filter(gf_local_nvtnl, NULL);
 	    if((F_ON(F_VIEW_SEL_URL, ps_global)
 		|| F_ON(F_VIEW_SEL_URL_HOST, ps_global)
--- pine4.55/pine/mailcmd.c.Lev	2003-03-28 01:35:54 +0300
+++ pine4.55/pine/mailcmd.c	2003-05-10 13:52:00 +0400
@@ -52,7 +52,7 @@
 
 #include "headers.h"
 #include "../c-client/imap4r1.h"
-
+#include "recodeg.h"
 
 /*
  * Internal Prototypes
@@ -66,6 +66,11 @@
 void      cmd_save PROTO((struct pine *, MAILSTREAM *, MSGNO_S *, int,
 			  CmdWhere));
 void      cmd_export PROTO((struct pine *, MSGNO_S *, int, int));
+void      cmd_fmt_save PROTO((struct pine *, MSGNO_S *));
+void      write_params PROTO((STORE_S *store, PARAMETER *param, char *except));
+void      write_x_recode PROTO((STORE_S *store));
+char     *get_charset PROTO((PARAMETER *param));
+char     *cmd_recode_charset PROTO((struct pine *, const char *, const char *));
 void      cmd_pipe PROTO((struct pine *, MSGNO_S *, int));
 PIPE_S	 *cmd_pipe_open PROTO((char *, char **, int, gf_io_t *));
 void	  prime_raw_text_getc PROTO((MAILSTREAM *, long));
@@ -1104,6 +1109,21 @@
 
 	break;
 
+          /*---------- Formatted Save ----------*/
+      case MC_FMTSAVE :
+        if(READONLY_FOLDER)
+            q_status_message(SM_ORDER, 0, 4,
+                             "Can't save message. Folder is read-only");
+	else
+	    cmd_fmt_save(state, msgmap);
+
+	break;
+
+          /*------- Recode message -----------*/
+      case MC_RECODE :
+        a_changed = cmd_recode(state);
+
+        break;
 
           /*---------- Expunge ----------*/
       case MC_EXPUNGE :
@@ -2151,6 +2171,455 @@
 }
 
 
+/*----------------------------------------------------------------------
+   Execute FORMATTED SAVE command (Lev)
+
+  Args: state  --  Various state info
+        msgmap --  map of c-client to local message numbers
+
+ Result: selected message formatted copy is saved to the current folder
+
+ ----*/
+void
+cmd_fmt_save(state, msgmap)
+     struct pine *state;
+     MSGNO_S     *msgmap;
+{
+    STORE_S  *store;
+    long      msgno = mn_m2raw(msgmap, mn_get_cur(msgmap));
+
+    /* This is from c-client/rfc822.h */
+    extern char *body_types[TYPEMAX + 1];
+
+    if(msgno <= 0L) {
+	cmd_cancelled("No messages for formatted save selected\n");
+	return;
+    }
+
+    if(store = so_get(CharStar, NULL, EDIT_ACCESS)) {
+	char       *header, *str;
+	const char       *old_charset, *charset;
+	STRING      message;
+        gf_io_t     pc;
+	int	    we_cancel, nfilts = 0;
+	FILTLIST_S  filters[4];
+	STRINGLIST  noh2      = {{"MIME-Version", 12}, NULL};
+	STRINGLIST  noh1      = {{"Content-Type", 12}, &noh2};
+	STRINGLIST  noheader  = {{"Content-Transfer-Encoding", 25}, &noh1};
+	BODY       *body;
+
+	memset(filters, 0, 4 * sizeof(FILTLIST_S));
+        we_cancel = busy_alarm(1, NULL, NULL, 0);
+
+	if(F_OFF(F_FSAVE_NO_WRAP, state)) {
+	    int width = state->ttyo->screen_cols;
+	    filters[nfilts].filter = gf_wrap;
+	    filters[nfilts++].data = gf_wrap_filter_opt(width, width, 0, 0);
+	}
+
+	if(recodeg_auto())
+	    recodeg_autosolve(state->atmts->body);
+	if(recodeg_used()) {
+	    filters[nfilts].filter = gf_recode;
+	    filters[nfilts++].data = recodeg_rules();
+	}
+
+	old_charset = get_charset(state->atmts->body->parameter);
+	/* the const-discarding is due to Pine sources 
+	   which do not care about const. */
+	if(old_charset && !strucmp((char*)old_charset, "us-ascii")) {
+	    STORE_S *tmp = so_get(CharStar, NULL, EDIT_ACCESS);
+	    gf_io_t tmp_pc;
+
+	    gf_set_so_writec(&tmp_pc, tmp);
+	    (void) detach(state->mail_stream, msgno,
+			  state->atmts->number, NULL, tmp_pc, NULL);
+	    gf_clear_so_writec(tmp);
+
+	    for(str = so_text(tmp); *str; str++)
+		if((unsigned char)*str & 0x80) {
+		    old_charset = NULL;
+    		    break;
+		}
+	    so_give(&tmp);
+	}
+
+	if(recodeg_used() || !old_charset) {
+	    charset = 
+	      recodeg_validcharset_static(old_charset ?
+					  old_charset 
+					  : state->VAR_CHAR_SET);
+	    if(we_cancel)
+		cancel_busy_alarm(0);
+
+	    charset = 
+	      cmd_recode_charset(state, 
+				 "Select a character set for a new message", 
+				 charset);
+
+	    if(!charset) {
+		cmd_cancelled("Formatted save");
+		return;
+	    }
+    	    we_cancel = busy_alarm(1, NULL, NULL, 0);
+	}
+	else
+	    charset = old_charset;
+
+    	(void) mail_fetchstructure(state->mail_stream, msgno, &body);
+	header = strdup(mail_fetchheader_full(state->mail_stream, msgno,
+		(body->type != TYPEMULTIPART) ? &noheader : NIL,
+		NIL, FT_NOT));
+
+	if((str = strrchr(header, '\r')) || (str = strrchr(header, '\n')))
+	    *str = '\0';
+
+	if(state->recode_header && recodeg_auto()) {
+	  char * const old = header;
+	  header = multiple_conv_str(recodeg_rules(), header);
+	  free(old);
+	}
+	so_puts(store, header);
+	free(header);
+	header= NULL;
+
+	if(body->type != TYPEMULTIPART) {
+	    so_puts(store, "MIME-Version: 1.0\r\nContent-Type: ");
+	    if(body->type != TYPEMAX) {
+		so_puts(store, body_types[body->type]);
+		so_puts(store, "/");
+		so_puts(store, body->subtype);
+	    }
+	    else
+		so_puts(store, "text/plain");
+	    so_puts(store, "; charset=");
+	    /* the const-discarding is due to Pine sources 
+	       which do not care about const. */
+	    so_puts(store, (char*)charset);
+	    write_params(store, body->parameter, "charset");
+	    so_puts(store, "\r\nContent-Transfer-Encoding: 8bit\r\n");
+	}
+
+	if(recodeg_used() && F_ON(F_ADD_X_RECODE, state))
+	    write_x_recode(store);
+
+	so_puts(store, "\r\n");
+
+	/* Message has a single part (no attachments) */
+	if(body->type != TYPEMULTIPART) {
+    	    gf_set_so_writec(&pc, store);
+	    (void) detach(state->mail_stream, msgno,
+			  state->atmts->number, NULL, pc,
+			  filters[0].filter ? filters : NULL);
+	    gf_clear_so_writec(store);
+	}
+	/* Multipart message */
+	else {
+	    ATTACH_S *att = state->atmts;
+	    char *boundary;
+	
+	    so_puts(store, "  This message is in MIME format. "
+		"The first part should be readable text,\r\n"
+	        "  while the remaining parts are likely unreadable "
+		"without MIME-aware tools.\r\n  Send mail to "
+		"mime@docserver.cac.washington.edu for more info.\r\n\r\n");
+
+	    boundary = rfc2231_get_param(body->parameter,
+				         "boundary", NULL, NULL);
+	    if(!boundary)
+		boundary = cpystr("-");
+
+	    so_puts(store, "--");
+	    so_puts(store, boundary);
+	    so_puts(store, "\r\nContent-Type: ");
+	    so_puts(store, body_types[att->body->type]);
+	    so_puts(store, "/");
+	    so_puts(store, att->body->subtype);
+	    so_puts(store, "; charset=");
+	    /* the const-discarding is due to Pine sources 
+	       which do not care about const. */
+	    so_puts(store, (char*)charset);
+	    write_params(store, att->body->parameter, "charset");
+	    so_puts(store, "\r\nContent-Transfer-Encoding: 8bit");
+	    if(att->body->id) {
+		so_puts(store, "\r\nContent-ID: ");
+		so_puts(store, att->body->id);
+	    }
+	    if(att->body->disposition.type) {
+		so_puts(store, "\r\nContent-Disposition: ");
+		so_puts(store, att->body->disposition.type);
+		write_params(store, att->body->disposition.parameter, NULL);
+	    }
+	    so_puts(store, "\r\n\r\n");
+
+    	    gf_set_so_writec(&pc, store);
+	    (void) detach(state->mail_stream, msgno,
+			  att->number, NULL, pc,
+			  filters[0].filter ? filters : NULL);
+	    gf_clear_so_writec(store);
+
+    	    so_puts(store, "\r\n--");
+	    so_puts(store, boundary);
+    	    so_puts(store, "\r\n");
+	    
+	    fs_give((void *) &boundary);
+	    
+	    for(att++; att->description; att++)
+		so_puts(store,
+			mail_fetch_mime(state->mail_stream, msgno,
+			att->number, NIL, NIL));
+	}
+
+	str = so_text(store);
+	INIT(&message, mail_string, (void *)str, strlen(str));
+
+	mail_append(state->mail_stream,
+		    state->mail_stream->mailbox, &message);
+	so_give(&store);
+
+	if(F_OFF(F_SAVE_WONT_DELETE, state)) {
+	    char seq[20];
+
+	    snprintf(seq, 20, "%ld", msgno);
+	    mail_flag(state->mail_stream, seq, "\\DELETED", ST_SET);
+	}
+        mail_check(state->mail_stream);
+
+	if(we_cancel)
+	    cancel_busy_alarm(0);
+
+	if(F_ON(F_FSAVE_STOP_RECODE, state)) {
+	    mn_set_cur(msgmap, mn_get_total(msgmap));
+	    recodeg_delall();
+	    recodeg_setauto(TRUE);
+	}
+	else if(F_ON(F_SAVE_ADVANCES, state))
+	    mn_set_cur(msgmap, mn_get_total(msgmap));
+	clear_index_cache();
+    }
+}
+
+
+/*----------------------------------------------------------------------
+   Write "X-Recoded" header line
+
+  Args: store --  The destination store
+
+ ----*/
+void
+write_x_recode(store)
+    STORE_S *store;
+{
+  char * buf = NULL;
+    so_puts(store, "X-Recoded: ");
+    buf = recodeg_info();
+    so_puts(store, "[");
+    so_puts(store, buf);
+    so_puts(store, "] by ");
+    so_puts(store, ps_global->ui.login);
+    so_puts(store, "@");
+    if(ps_global->userdomain)
+	so_puts(store, ps_global->userdomain);
+    else
+	so_puts(store, ps_global->maildomain);
+    so_puts(store, "\r\n");
+    free(buf);
+}
+
+
+/*----------------------------------------------------------------------
+   Write parameters of a header line (Content-Type, Content-Disposition,
+   etc.)
+
+  Args: store   --  The destination store
+        param   --  PARAMETER structure chain
+	except  --  do not write this parameter.
+
+ ----*/
+void
+write_params(store, param, except)
+    STORE_S *store;
+    PARAMETER *param;
+    char *except;
+{
+    if(!except)
+	except = "";
+
+    while(param) {
+	if(strucmp(param->attribute, except)) {
+	    so_puts(store, "; ");
+	    so_puts(store, param->attribute);
+	    so_puts(store, "=");
+	    so_puts(store, param->value);
+	}
+	param = param->next;
+    }
+}
+
+
+/*----------------------------------------------------------------------
+   Returns the value of "charset" from parameter list, if exists.
+
+  Args: param   --  PARAMETER structure chain
+
+ ----*/
+char *
+get_charset(param)
+    PARAMETER *param;
+{
+    while(param)
+	if(!strucmp(param->attribute, "charset"))
+	    return param->value;
+	else
+	    param = param->next;
+    return NULL;
+}
+
+
+/*----------------------------------------------------------------------
+   Execute RECODE message command (Lev)
+
+  Args: state --  Various state info
+
+ Result: view of messages is changed to use 
+
+ ----*/
+int
+cmd_recode(state)
+    struct pine *state;
+{
+    ESCKEY_S menu[] = {
+	{'a', 'a', "A", (recodeg_auto()) ? "Manual" : "Auto"},
+	{'h', 'h', "H", state->recode_header ? "NoHead" : "Header"},
+	{'+', '+', "+", "Add rule"},
+	{'-', '-', "-", "Delete last"},
+	{'d', 'd', "D", "Delete all"},
+	{-1, 0, NULL, NULL}
+    };
+    char * tmp_info = NULL;
+    char prompt[1001] = "Recoding: [";
+	strncat (prompt, tmp_info = recodeg_info(), 1000 - strlen(prompt) - 1);    
+    strncat(prompt, "]", 1000 - strlen(prompt));
+    free(tmp_info);
+
+    switch(radio_buttons(prompt, -FOOTER_ROWS(state),
+			 menu, 'a', 'q', NO_HELP, RB_NORM))
+    {
+	case 'a':
+	    recodeg_setauto(!recodeg_auto());
+	    q_status_message1(SM_ORDER, 0, 4,
+		"Automatic recoding is now %s",
+                recodeg_auto() ? "on" : "off");
+            recodeg_delall();
+	    return 1;
+
+    case 'h':
+      state->recode_header = !state->recode_header;
+      q_status_message3(SM_ORDER, 0, 3,
+			"Recoding of headers is now o%.200s.  Use %.200s to turn back o%.200s",
+			state->recode_header ? "n" : "ff",
+			"^R H",
+			!state->recode_header ? "n" : "ff");
+      return 1;
+
+	case '+': {
+	    char *from, *to;
+
+	    if(!(from = cmd_recode_charset(state, "Recode from", NULL)) ||
+	       !(to = cmd_recode_charset(state, "Recode to", NULL)))
+		return 0;
+	    if(recodeg_addrule(from, to)) {
+		if(errno == EINVAL)
+		    q_status_message2(SM_ORDER, 3, 4,
+			"Recoding from %s to %s is not supported",
+			from, to);
+		else
+		    q_status_message1(SM_ORDER, 3, 4,
+			"Recoding cancelled: %s",
+			error_description(errno));
+		return 0;
+	    }
+	    recodeg_setauto(FALSE);
+	    q_status_message2(SM_ORDER, 0, 4,
+		"Recoding from %s to %s appended",
+		from, to);
+    	    return 1;
+	}
+
+	case '-':
+	    recodeg_setauto(FALSE);
+	    if(!recodeg_used()) {
+		q_status_message(SM_ORDER, 0, 4,
+			"No recoding rule is in use");
+		return 0;
+	    }
+	    recodeg_dellast();
+	    q_status_message(SM_ORDER, 0, 4,
+		"Last recoding rule deleted");
+	    return 1;
+	
+	case 'd':
+	    recodeg_setauto(FALSE);
+	    if(!recodeg_used()) {
+		q_status_message(SM_ORDER, 0, 4,
+			"No recoding rule is in use");
+		return 0;
+	    }
+	    recodeg_delall();
+	    q_status_message(SM_ORDER, 0, 4,
+		"All recoding rules deleted");
+	    return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------
+   This function implements a charset menu (Lev)
+
+  Args: state	       -- pine state structure
+        prompt         -- prompt string
+	def            -- default charset, if NULL, take default
+	                  from setup
+
+ Result: the string constant with selected charset name, NULL if cancelled.
+
+ ----*/
+char *
+cmd_recode_charset(state, prompt, def)
+    struct pine *state;
+    const char *prompt, *def;
+{
+	/* the second field is a document charset name */
+    static ESCKEY_S encs[] = {
+	{'k', (int)"koi8-r", 		"K", "KOI8-R"		},
+	{'u', (int)"koi8-u", 		"U", "KOI8-U"		},
+	{'w', (int)"windows-1251", 	"W", "CP1251 (Win)"	},
+	{'d', (int)"cp866", 		"D", "CP866 (DOS)"	},
+	{'i', (int)"iso-8859-5", 	"I", "ISO-8859-5"	},
+	{'p', (int)"paratype-154", 	"P", "PT154 (Asian)"},
+	{'7', (int)"koi-7", 		"7", "KOI-7 (7 bit)"},
+	{'f', (int)"utf-8", 		"F", "UTF-8 (Unicode)"},
+	{'g', (int)"utf-7", 		"G", "UTF-7 (Unicode)"},
+	{'h', (int)"ucs-4", 		"H", "UCS-4 (Unicode)"},
+	{-1, 0, NULL, NULL}
+    };
+    char buf[1000];
+    char *res;
+    if(!def && !(def = state->VAR_CHAR_SET)) {
+	def = "";
+	snprintf(buf, 1000, "%s:", prompt);
+    }
+    else
+	snprintf(buf, 1000, "%s [%s]:", prompt, def);
+
+    res = (char *)radio_buttons(buf, -FOOTER_ROWS(state), encs,
+			        (int)def,
+			        (int)"", NO_HELP, RB_NORM);
+    if(res == NULL || *res == '\0')
+	return NULL;
+    return res;
+}
+
 
 /*----------------------------------------------------------------------
    Execute FLAG message command
 
design & coding: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
current maintainer: Michael Shigorin