1/* chatc.c
2   Subroutines to handle chat script commands.
3
4   Copyright (C) 1992, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP uuconf library.
7
8   This library is free software; you can redistribute it and/or
9   modify it under the terms of the GNU Library General Public License
10   as published by the Free Software Foundation; either version 2 of
11   the License, or (at your option) any later version.
12
13   This library is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   Library General Public License for more details.
17
18   You should have received a copy of the GNU Library General Public
19   License along with this library; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucnfi.h"
26
27#if USE_RCS_ID
28const char _uuconf_chatc_rcsid[] = "$Id: chatc.c,v 1.10 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31#include <ctype.h>
32#include <errno.h>
33
34static int icchat P((pointer pglobal, int argc, char **argv,
35		     pointer pvar, pointer pinfo));
36static int icchat_fail P((pointer pglobal, int argc, char **argv,
37			  pointer pvar, pointer pinfo));
38static int icunknown P((pointer pglobal, int argc, char **argv,
39			pointer pvar, pointer pinfo));
40
41/* The chat script commands.  */
42
43static const struct cmdtab_offset asChat_cmds[] =
44{
45  { "chat", UUCONF_CMDTABTYPE_FN,
46      offsetof (struct uuconf_chat, uuconf_pzchat), icchat },
47  { "chat-program", UUCONF_CMDTABTYPE_FULLSTRING,
48      offsetof (struct uuconf_chat, uuconf_pzprogram), NULL },
49  { "chat-timeout", UUCONF_CMDTABTYPE_INT,
50      offsetof (struct uuconf_chat, uuconf_ctimeout), NULL },
51  { "chat-fail", UUCONF_CMDTABTYPE_FN | 2,
52      offsetof (struct uuconf_chat, uuconf_pzfail), icchat_fail },
53  { "chat-seven-bit", UUCONF_CMDTABTYPE_BOOLEAN,
54      offsetof (struct uuconf_chat, uuconf_fstrip), NULL },
55  { NULL, 0, 0, NULL }
56};
57
58#define CCHAT_CMDS (sizeof asChat_cmds / sizeof asChat_cmds[0])
59
60/* Handle a chat script command.  The chat script commands are entered
61   as UUCONF_CMDTABTYPE_PREFIX, and the commands are routed to this
62   function.  We copy the command table onto the stack and repoint it
63   at qchat in order to make the function reentrant.  The return value
64   can include UUCONF_CMDTABRET_KEEP, but should not include
65   UUCONF_CMDTABRET_EXIT.  */
66
67int
68_uuconf_ichat_cmd (qglobal, argc, argv, qchat, pblock)
69     struct sglobal *qglobal;
70     int argc;
71     char **argv;
72     struct uuconf_chat *qchat;
73     pointer pblock;
74{
75  char *zchat;
76  struct uuconf_cmdtab as[CCHAT_CMDS];
77  int iret;
78
79  /* This is only invoked when argv[0] will contain the string "chat";
80     the specific chat script command comes after that point.  */
81  for (zchat = argv[0]; *zchat != '\0'; zchat++)
82    if ((*zchat == 'c' || *zchat == 'C')
83	&& strncasecmp (zchat, "chat", sizeof "chat" - 1) == 0)
84      break;
85  if (*zchat == '\0')
86    return UUCONF_SYNTAX_ERROR;
87  argv[0] = zchat;
88
89  _uuconf_ucmdtab_base (asChat_cmds, CCHAT_CMDS, (char *) qchat, as);
90
91  iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as, pblock,
92			  icunknown, 0, pblock);
93
94  /* If chat-program was specified with no arguments, treat that as no
95     chat-program.  This may be used to override an earlier
96     chat-program.  There is a space leak here.  */
97  if (qchat->uuconf_pzprogram != NULL && qchat->uuconf_pzprogram[0] == NULL)
98    qchat->uuconf_pzprogram = NULL;
99
100  return iret &~ UUCONF_CMDTABRET_EXIT;
101}
102
103/* Handle the "chat" command.  This breaks up substrings in expect
104   strings, and sticks the arguments into a NULL terminated array.  */
105
106static int
107icchat (pglobal, argc, argv, pvar, pinfo)
108     pointer pglobal;
109     int argc;
110     char **argv;
111     pointer pvar;
112     pointer pinfo;
113{
114  struct sglobal *qglobal = (struct sglobal *) pglobal;
115  char ***ppz = (char ***) pvar;
116  pointer pblock = pinfo;
117  int i;
118
119  *ppz = NULL;
120
121  for (i = 1; i < argc; i += 2)
122    {
123      char *z, *zdash;
124      int iret;
125
126      /* Break the expect string into substrings.  */
127      z = argv[i];
128      zdash = strchr (z, '-');
129      while (zdash != NULL)
130	{
131	  *zdash = '\0';
132	  iret = _uuconf_iadd_string (qglobal, z, TRUE, FALSE, ppz,
133				      pblock);
134	  if (iret != UUCONF_SUCCESS)
135	    return iret;
136	  *zdash = '-';
137	  z = zdash;
138	  zdash = strchr (z + 1, '-');
139	}
140
141      iret = _uuconf_iadd_string (qglobal, z, FALSE, FALSE, ppz, pblock);
142      if (iret != UUCONF_SUCCESS)
143	return iret;
144
145      /* Add the send string without breaking it up.  If it starts
146	 with a dash we must replace it with an escape sequence, to
147	 prevent it from being interpreted as a subsend.  */
148
149      if (i + 1 < argc)
150	{
151	  if (argv[i + 1][0] != '-')
152	    iret = _uuconf_iadd_string (qglobal, argv[i + 1], FALSE,
153					FALSE, ppz, pblock);
154	  else
155	    {
156	      size_t clen;
157
158	      clen = strlen (argv[i + 1]);
159	      z = uuconf_malloc (pblock, clen + 2);
160	      if (z == NULL)
161		{
162		  qglobal->ierrno = errno;
163		  return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
164		}
165	      z[0] = '\\';
166	      memcpy ((pointer) (z + 1), (pointer) argv[i + 1], clen + 1);
167	      iret = _uuconf_iadd_string (qglobal, z, FALSE, FALSE, ppz,
168					  pblock);
169	    }
170	  if (iret != UUCONF_SUCCESS)
171	    return iret;
172	}
173    }
174
175  return UUCONF_CMDTABRET_KEEP;
176}
177
178/* Add a new chat failure string.  */
179
180/*ARGSUSED*/
181static int
182icchat_fail (pglobal, argc, argv, pvar, pinfo)
183     pointer pglobal;
184     int argc ATTRIBUTE_UNUSED;
185     char **argv;
186     pointer pvar;
187     pointer pinfo;
188{
189  struct sglobal *qglobal = (struct sglobal *) pglobal;
190  char ***ppz = (char ***) pvar;
191  pointer pblock = pinfo;
192
193  return _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, ppz, pblock);
194}
195
196/* Return a syntax error for an unknown command.  */
197
198/*ARGSUSED*/
199static int
200icunknown (pglobal, argc, argv, pvar, pinfo)
201     pointer pglobal ATTRIBUTE_UNUSED;
202     int argc ATTRIBUTE_UNUSED;
203     char **argv ATTRIBUTE_UNUSED;
204     pointer pvar ATTRIBUTE_UNUSED;
205     pointer pinfo ATTRIBUTE_UNUSED;
206{
207  return UUCONF_SYNTAX_ERROR;
208}
209