diff -ru ../original/linux/fs/nls/nls_base.c linux/fs/nls/nls_base.c
--- ../original/linux/fs/nls/nls_base.c	Mon May 10 13:15:20 1999
+++ linux/fs/nls/nls_base.c	Thu May 13 14:32:46 1999
@@ -3,6 +3,7 @@
  *
  * Native language support--charsets and unicode translations.
  * By Gordon Chaffee 1996, 1997
+ * 1999 charset-to-charset tables added by Artem Ryabov
  *
  */
 
@@ -239,7 +240,113 @@
 {
 	nls->dec_use_count();
 }
+/* Artem start insert */
 
+static void build_c2c_table(struct c2c_nls_table *table, 
+	struct nls_table *nls_local, struct nls_table *nls_remote)
+{
+	unsigned char ch, cl;
+	unsigned char *uni_page;
+	int i,j;
+
+	strncpy(table->remote_charset,nls_remote->charset,
+		sizeof(table->remote_charset));
+	strncpy(table->local_charset,nls_local->charset,
+		sizeof(table->local_charset));
+	memset(table->l2r,'\0',256);
+	memset(table->r2l,'\0',256);
+	/* fill table from nls */
+	for (i=1; i<256; i++) {
+		cl = nls_local->charset2uni[i].uni1;
+		ch = nls_local->charset2uni[i].uni2;
+		uni_page = nls_remote->page_uni2charset[ch];
+		if (uni_page && uni_page[cl] && ! table->l2r[i] ) {
+			table->l2r[i] = uni_page[cl];
+			table->r2l[uni_page[cl]] = i;
+		}
+		cl = nls_remote->charset2uni[i].uni1;
+		ch = nls_remote->charset2uni[i].uni2;
+		uni_page = nls_local->page_uni2charset[ch];
+		if (uni_page && uni_page[cl] && ! table->r2l[i] ) {
+			table->r2l[i] = uni_page[cl];
+			table->l2r[uni_page[cl]]=i;
+		}
+	}
+	/* fill zero positions */
+	for (i=1; i<256; i++) {
+		if (table->l2r[i] || table->r2l[i])
+			continue;
+		table->l2r[i] = i;
+		table->r2l[i] = i;
+	}
+	for (i=1, j=1; i<256; i++) {
+		if (table->l2r[i])
+			continue;
+		for ( ; j<256 && table->r2l[j]; j++);
+		if (j>=256)
+			break; /* it can't be reached. just in case :-) */
+		table->l2r[i] = j;
+		table->r2l[j] = i;
+	}
+}
+
+static struct c2c_nls_table *first_c2c_table=NULL;
+struct c2c_nls_table *load_c2c_nls_table(char *local_charset, 
+			char *remote_charset)
+{
+	struct nls_table *nls_local, *nls_remote;
+	struct c2c_nls_table *table;
+	struct c2c_nls_table *last=NULL;
+
+	for(table=first_c2c_table; table; last=table,table=table->next)
+		if( ! strncmp(local_charset, table->local_charset,
+			      sizeof(table->local_charset)) &&
+		    ! strncmp(remote_charset, table->remote_charset,
+			      sizeof(table->remote_charset)))
+			break;
+	if(table) {
+		table->count++;
+		return(table);
+	}
+	nls_remote=load_nls(remote_charset);
+	if (nls_remote) {
+		nls_local=load_nls(local_charset);
+		if(nls_local)	{
+			table=kmalloc(sizeof(struct c2c_nls_table), GFP_KERNEL);
+			if(table) {
+				if(last)
+					last->next=table;
+				else
+					first_c2c_table=table;
+				table->next=NULL;
+				table->count=1;
+				build_c2c_table(table, nls_local, nls_remote);
+			}
+			unload_nls(nls_local);
+		}
+		unload_nls(nls_remote);
+	}
+	return(table);
+}
+
+void unload_c2c_nls_table(struct c2c_nls_table *table)
+{
+	struct c2c_nls_table *prev;
+	if(--table->count)
+		return;
+	if (table==first_c2c_table)
+		first_c2c_table=table->next;
+	else {
+		for(prev=first_c2c_table;prev && prev->next!=table;
+		    prev=prev->next);
+		if (!prev)
+			return; /* there is error in chain struture */
+		prev->next=table->next;
+	}
+	kfree(table);
+}
+
+/* Artem end insert */
 struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
 	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
diff -ru ../original/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- ../original/linux/fs/smbfs/inode.c	Mon May 10 13:15:54 1999
+++ linux/fs/smbfs/inode.c	Wed May 12 17:07:48 1999
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *  Copyright (C) 1997 by Volker Lendecke
+ *  1999 Nls addon by Artem Ryabov
  *
  */
 
@@ -327,6 +328,12 @@
 		smb_dont_catch_keepalive(server);
 		fput(server->sock_file);
 	}
+/* Artem start insert */
+	if (server->s_table) {
+		unload_c2c_nls_table(server->s_table);
+		server->s_table=NULL;
+	}
+/* Artem end insert */
 
 	if (server->conn_pid)
 	       kill_proc(server->conn_pid, SIGTERM, 1);
@@ -402,6 +409,9 @@
 	else if (mnt->version & SMB_FIX_DIRATTR)
 		printk("SMBFS: Using dir ff getattr\n");
 
+/* Artem start insert */
+	sb->u.smbfs_sb.s_table=NULL;
+/* Artem end insert */
 	/*
 	 * Keep the super block locked while we get the root inode.
 	 */
diff -ru ../original/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- ../original/linux/fs/smbfs/ioctl.c	Tue May 11 18:18:26 1999
+++ linux/fs/smbfs/ioctl.c	Thu May 13 14:37:22 1999
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995, 1996 by Volker Lendecke
  *  Copyright (C) 1997 by Volker Lendecke
+ *  1999 Nls addon by Artem Ryabov
  *
  */
 
@@ -51,6 +52,68 @@
 		}
 		break;
 	}
+/* Artem start insert */
+	case SMB_IOC_SETCHARSETS:
+		if ((permission(inode, MAY_WRITE) != 0) &&
+		    (current->uid != server->mnt->mounted_uid)) {
+			result = -EACCES;
+			break;
+		}
+		{
+			struct smb_nls_ioctl user;
+
+			struct c2c_nls_table *table;
+			struct c2c_nls_table *old_table;
+			
+			if (copy_from_user(&user, 
+					   (struct smb_nls_ioctl*)arg,
+					   sizeof(user))) {
+				result = -EFAULT;
+				break;
+			}
+
+			if (!user.local_charset[0] && !user.smb_charset[0]) {
+				/* turn off translation */
+				table=NULL;
+			} else {
+				if (!user.local_charset[0] ||
+				    !user.smb_charset[0]) {
+					result = -EBADRQC;
+					break;
+				}
+				table=load_c2c_nls_table(user.local_charset,
+							 user.smb_charset);
+				if (!table) {
+					result = -EBADRQC;
+					break;
+				}
+			}
+
+			old_table = server->s_table;
+			server->s_table = table;
+			if (old_table) unload_c2c_nls_table(old_table);
+			result = 0;
+		}
+		break;
+	case SMB_IOC_GETCHARSETS:
+		{
+			struct smb_nls_ioctl user;
+			strncpy(user.local_charset,
+				server->s_table->local_charset,
+				sizeof(user.local_charset));
+			strncpy(user.smb_charset,
+				server->s_table->remote_charset,
+				sizeof(user.smb_charset));
+
+			if (copy_to_user((struct smb_nls_ioctl*)arg,
+				&(user),
+				sizeof(user))) {
+				result = -EFAULT;
+			} else {
+				result = 0;
+			}
+		}
+/* Artem end insert */
 	default:
 	}
 	return result;
diff -ru ../original/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- ../original/linux/fs/smbfs/proc.c	Mon May 10 13:15:56 1999
+++ linux/fs/smbfs/proc.c	Thu May 13 14:47:42 1999
@@ -7,6 +7,7 @@
  *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  *  28/09/97 - Fixed smb_d_path [now smb_build_path()] to be non-recursive
  *             by Riccardo Facchetti
+ *  1999 Nls addon by Artem Ryabov
  */
 
 #include <linux/types.h>
@@ -79,6 +80,18 @@
 		*(end--) = c;
 	}
 }
+/* Artem start insert */
+
+static void translate_name(unsigned char *op, const unsigned char *ip, int len,
+			   const unsigned char *table)
+{
+	for (; *ip && len > 0 ; len--, ip++)
+		*op++ = *(table+*ip);
+	if (len > 0)
+		*op = 0;
+}
+
+/* Artem end insert */
 
 /*****************************************************************************/
 /*                                                                           */
@@ -104,7 +117,10 @@
  * smb_build_path: build the path to entry and name storing it in buf.
  * The path returned will have the trailing '\0'.
  */
-static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf)
+/* Artem change begin */
+static int smb_build_path(struct smb_sb_info *server, struct dentry * entry, 
+			  struct qstr * name, char * buf)
+/* Artem change end */
 {
 	char *path = buf;
 
@@ -126,7 +142,13 @@
 	 * and store it in reversed order [see reverse_string()]
 	 */
 	for (;;) {
-		memcpy(path, entry->d_name.name, entry->d_name.len);
+/* Artem start insert */
+		if(server->s_table)
+			translate_name(path, entry->d_name.name,
+				entry->d_name.len, server->s_table->l2r);
+		else
+/* Artem end insert */
+			memcpy(path, entry->d_name.name, entry->d_name.len);
 		reverse_string(path, entry->d_name.len);
 		path += entry->d_name.len;
 
@@ -144,7 +166,13 @@
 	if (name != NULL) {
 		*(path++) = '\\';
 name_and_out:
-		memcpy(path, name->name, name->len);
+/* Artem start insert */
+		if(server->s_table)
+			translate_name(path, name->name, name->len,
+				       server->s_table->l2r);
+		else
+/* Artem end insert */
+			memcpy(path, name->name, name->len);
 		path += name->len;
 	}
 out:
@@ -157,7 +185,7 @@
 {
 	char *start = buf;
 
-	buf += smb_build_path(dir, name, buf);
+	buf += smb_build_path(server, dir, name, buf); /* Artem change */
 
 	if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
 		str_upper(start, buf - start);
@@ -1282,6 +1310,11 @@
 	{
 		len = 12;
 	}
+/* Artem insert start */
+	if(server->s_table)
+		translate_name(entry->name, entry->name, len,
+			       server->s_table->r2l);
+/* Artem insert end */
 	/*
 	 * Trim trailing blanks for Pathworks servers
 	 */
@@ -1454,6 +1487,11 @@
 		len = *((unsigned char *) p + 26);
 		entry->len = len;
 		entry->name = p + 27;
+/* Artem insert start */
+		if(server->s_table)
+			translate_name(entry->name, entry->name, len,
+				       server->s_table->r2l);
+/* Artem insert end */
 		result = p + 28 + len;
 		break;
 
@@ -1464,6 +1502,11 @@
 		if (len > 255)
 			len = 255;
 		entry->name = p + 12;
+/* Artem insert start */
+		if(server->s_table)
+			translate_name(entry->name, entry->name, len,
+				       server->s_table->r2l);
+/* Artem insert end */
 		/*
 		 * Kludge alert: Win NT 4.0 adds a trailing null byte and
 		 * counts it in the name length, but Win 95 doesn't.  Hence
diff -ru ../original/linux/include/linux/nls.h linux/include/linux/nls.h
--- ../original/linux/include/linux/nls.h	Mon May 10 13:16:42 1999
+++ linux/include/linux/nls.h	Thu May 13 14:51:04 1999
@@ -1,3 +1,12 @@
+/*
+ *  nls.h
+ *
+ *  1999 charset-to-charset tables added by Artem Ryabov
+ */
+/* Artem start insert */
+#ifndef _LINUX_NLS_H
+#define _LINUX_NLS_H
+/* Artem end insert */
 struct nls_unicode {
 	unsigned char uni1;
 	unsigned char uni2;
@@ -12,6 +21,22 @@
 	void (*dec_use_count) (void);
 	struct nls_table *next;
 };
+/* Artem start insert */
+#define NLS_CHARSET_LEN 20
+
+struct c2c_nls_table {
+	unsigned char remote_charset[NLS_CHARSET_LEN];	/* charset name used remote */
+	unsigned char local_charset[NLS_CHARSET_LEN];	/* charset name used local */
+	unsigned char r2l[256];				/* translation table from remote to local */
+	unsigned char l2r[256];				/* translation table from local to remote */
+	int count;					/* uses count */
+	struct c2c_nls_table *next;			/* next tables in chain */
+};
+
+extern struct c2c_nls_table *load_c2c_nls_table(char *local_charset,char *remote_charset);
+extern void unload_c2c_nls_table(struct c2c_nls_table *table);
+
+/* Artem end insert */
 
 /* nls.c */
 extern int init_nls(void);
@@ -54,3 +79,6 @@
 extern int init_nls_cp869(void);
 extern int init_nls_cp874(void);
 extern int init_nls_koi8_r(void);
+/* Artem start insert */
+#endif
+/* Artem end insert */
diff -ru ../original/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- ../original/linux/include/linux/smb_fs.h	Wed May 12 17:50:08 1999
+++ linux/include/linux/smb_fs.h	Thu May 13 14:49:58 1999
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
  *  Copyright (C) 1997 by Volker Lendecke
+ *  1999 Nls addon by Artem Ryabov
  *
  */
 
@@ -11,11 +12,24 @@
 
 #include <linux/smb.h>
 
+/* Artem start insert */
+#include <linux/nls.h>
+/* NLS charsets by ioctl */
+struct smb_nls_ioctl
+{
+	char smb_charset[NLS_CHARSET_LEN];
+	char local_charset[NLS_CHARSET_LEN];
+};
+/* Artem end insert */
 /*
  * ioctl commands
  */
 #define	SMB_IOC_GETMOUNTUID		_IOR('u', 1, __kernel_uid_t)
 #define SMB_IOC_NEWCONN                 _IOW('u', 2, struct smb_conn_opt)
+/* Artem start insert */
+#define SMB_IOC_GETCHARSETS		_IOWR('u', 3, struct smb_nls_ioctl)
+#define SMB_IOC_SETCHARSETS		_IOR('u', 3, struct smb_nls_ioctl)
+/* Artem end insert */
 
 #ifdef __KERNEL__
 
diff -ru ../original/linux/include/linux/smb_fs_sb.h linux/include/linux/smb_fs_sb.h
--- ../original/linux/include/linux/smb_fs_sb.h	Mon May 10 13:17:34 1999
+++ linux/include/linux/smb_fs_sb.h	Thu May 13 14:16:34 1999
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
  *  Copyright (C) 1997 by Volker Lendecke
+ *  1999 Nls addon by Artem Ryabov
  *
  */
 
@@ -13,6 +14,9 @@
 
 #include <linux/types.h>
 #include <linux/smb.h>
+/* Artem start insert */
+#include <linux/nls.h>
+/* Artem end insert */
 
 /* Get the server for the specified dentry */
 #define server_from_dentry(dentry) &dentry->d_sb->u.smbfs_sb
@@ -43,6 +47,9 @@
 
         /* We use our on data_ready callback, but need the original one */
         void *data_ready;
+/* Artem start insert */
+	struct c2c_nls_table *s_table;
+/* Artem end insert */
 };
 
 #endif /* __KERNEL__ */
