1/*
2   Unix SMB/CIFS implementation.
3   Samba module with developer tools
4   Copyright (C) Andrew Tridgell 2001
5   Copyright (C) Jelmer Vernooij 2002
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23
24static struct {
25	char from;
26	char *to;
27	int len;
28} weird_table[] = {
29	{'q', "^q^", 3},
30	{'Q', "^Q^", 3},
31	{0, NULL}
32};
33
34static size_t weird_pull(void *cd, const char **inbuf, size_t *inbytesleft,
35			 char **outbuf, size_t *outbytesleft)
36{
37	while (*inbytesleft >= 1 && *outbytesleft >= 2) {
38		int i;
39		int done = 0;
40		for (i=0;weird_table[i].from;i++) {
41			if (strncmp((*inbuf),
42				    weird_table[i].to,
43				    weird_table[i].len) == 0) {
44				if (*inbytesleft < weird_table[i].len) {
45					DEBUG(0,("ERROR: truncated weird string\n"));
46					/* smb_panic("weird_pull"); */
47
48				} else {
49					(*outbuf)[0] = weird_table[i].from;
50					(*outbuf)[1] = 0;
51					(*inbytesleft)  -= weird_table[i].len;
52					(*outbytesleft) -= 2;
53					(*inbuf)  += weird_table[i].len;
54					(*outbuf) += 2;
55					done = 1;
56					break;
57				}
58			}
59		}
60		if (done) continue;
61		(*outbuf)[0] = (*inbuf)[0];
62		(*outbuf)[1] = 0;
63		(*inbytesleft)  -= 1;
64		(*outbytesleft) -= 2;
65		(*inbuf)  += 1;
66		(*outbuf) += 2;
67	}
68
69	if (*inbytesleft > 0) {
70		errno = E2BIG;
71		return -1;
72	}
73
74	return 0;
75}
76
77static size_t weird_push(void *cd, const char **inbuf, size_t *inbytesleft,
78			 char **outbuf, size_t *outbytesleft)
79{
80	int ir_count=0;
81
82	while (*inbytesleft >= 2 && *outbytesleft >= 1) {
83		int i;
84		int done=0;
85		for (i=0;weird_table[i].from;i++) {
86			if ((*inbuf)[0] == weird_table[i].from &&
87			    (*inbuf)[1] == 0) {
88				if (*outbytesleft < weird_table[i].len) {
89					DEBUG(0,("No room for weird character\n"));
90					/* smb_panic("weird_push"); */
91				} else {
92					memcpy(*outbuf, weird_table[i].to,
93					       weird_table[i].len);
94					(*inbytesleft)  -= 2;
95					(*outbytesleft) -= weird_table[i].len;
96					(*inbuf)  += 2;
97					(*outbuf) += weird_table[i].len;
98					done = 1;
99					break;
100				}
101			}
102		}
103		if (done) continue;
104
105		(*outbuf)[0] = (*inbuf)[0];
106		if ((*inbuf)[1]) ir_count++;
107		(*inbytesleft)  -= 2;
108		(*outbytesleft) -= 1;
109		(*inbuf)  += 2;
110		(*outbuf) += 1;
111	}
112
113	if (*inbytesleft == 1) {
114		errno = EINVAL;
115		return -1;
116	}
117
118	if (*inbytesleft > 1) {
119		errno = E2BIG;
120		return -1;
121	}
122
123	return ir_count;
124}
125
126struct charset_functions weird_functions = {"WEIRD", weird_pull, weird_push};
127
128NTSTATUS charset_weird_init(void)
129{
130	return smb_register_charset(&weird_functions);
131}
132