1/* parse.c
2   Parse a UUCP command string.
3
4   Copyright (C) 1991, 1992, 1993, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; 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 "uucp.h"
26
27#if USE_RCS_ID
28const char parse_rcsid[] = "$Id: parse.c,v 1.11 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31#include "uudefs.h"
32
33/* Local functions.  */
34
35static void ulunquote_cmd P((struct scmd *qcmd));
36
37/* Parse a UUCP command string into an scmd structure.  This is called
38   by the 'g' protocol and the UNIX command file reading routines.  It
39   destroys the string it is passed, and the scmd string pointers are
40   left pointing into it.  For the convenience of the Unix work file
41   routines, it will parse "P" into a simple 'P' command (representing
42   a poll file).  If 'q' appears in the options, it will unquote all
43   the relevant strings.  It returns TRUE if the string is
44   successfully parsed, FALSE otherwise.  */
45
46boolean
47fparse_cmd (zcmd, qcmd)
48     char *zcmd;
49     struct scmd *qcmd;
50{
51  char *z, *zend;
52
53  z = strtok (zcmd, " \t\n");
54  if (z == NULL)
55    return FALSE;
56
57  qcmd->bcmd = *z;
58  if (qcmd->bcmd != 'S'
59      && qcmd->bcmd != 'R'
60      && qcmd->bcmd != 'X'
61      && qcmd->bcmd != 'E'
62      && qcmd->bcmd != 'H'
63      && qcmd->bcmd != 'P')
64    return FALSE;
65
66  qcmd->bgrade = '\0';
67  qcmd->pseq = NULL;
68  qcmd->zfrom = NULL;
69  qcmd->zto = NULL;
70  qcmd->zuser = NULL;
71  qcmd->zoptions = NULL;
72  qcmd->ztemp = NULL;
73  qcmd->imode = 0666;
74  qcmd->znotify = NULL;
75  qcmd->cbytes = -1;
76  qcmd->zcmd = NULL;
77  qcmd->ipos = 0;
78
79  /* Handle hangup commands specially.  If it's just "H", return
80     the command 'H' to indicate a hangup request.  If it's "HY"
81     return 'Y' and if it's "HN" return 'N'.  */
82  if (qcmd->bcmd == 'H')
83    {
84      if (z[1] != '\0')
85	{
86	  if (z[1] == 'Y')
87	    qcmd->bcmd = 'Y';
88	  else if (z[1] == 'N')
89	    qcmd->bcmd = 'N';
90	  else
91	    return FALSE;
92	}
93
94      return TRUE;
95    }
96  if (qcmd->bcmd == 'P')
97    return TRUE;
98
99  if (z[1] != '\0')
100    return FALSE;
101
102  z = strtok ((char *) NULL, " \t\n");
103  if (z == NULL)
104    return FALSE;
105  qcmd->zfrom = z;
106
107  z = strtok ((char *) NULL, " \t\n");
108  if (z == NULL)
109    return FALSE;
110  qcmd->zto = z;
111
112  z = strtok ((char *) NULL, " \t\n");
113  if (z == NULL)
114    return FALSE;
115  qcmd->zuser = z;
116
117  z = strtok ((char *) NULL, " \t\n");
118  if (z == NULL || *z != '-')
119    return FALSE;
120  qcmd->zoptions = z + 1;
121
122  if (qcmd->bcmd == 'X')
123    {
124      ulunquote_cmd (qcmd);
125      return TRUE;
126    }
127
128  if (qcmd->bcmd == 'R')
129    {
130      z = strtok ((char *) NULL, " \t\n");
131      if (z != NULL)
132	{
133	  if (strcmp (z, "dummy") != 0)
134	    {
135	      /* This may be the maximum number of bytes the remote
136		 system wants to receive, if it using Taylor UUCP size
137		 negotiation.  */
138	      qcmd->cbytes = strtol (z, &zend, 0);
139	      if (*zend != '\0')
140		qcmd->cbytes = -1;
141	    }
142	  else
143	    {
144	      /* This is from an SVR4 system, and may include the
145		 position at which to start sending the file.  The
146		 next fields are the mode bits, the remote owner (?),
147		 the remote temporary file name, and finally the
148		 restart position.  */
149	      if (strtok ((char *) NULL, " \t\n") != NULL
150		  && strtok ((char *) NULL, " \t\n") != NULL
151		  && strtok ((char *) NULL, " \t\n") != NULL)
152		{
153		  z = strtok ((char *) NULL, " \t\n");
154		  if (z != NULL)
155		    {
156		      qcmd->ipos = strtol (z, &zend, 0);
157		      if (*zend != '\0')
158			qcmd->ipos = 0;
159		    }
160		}
161	    }
162	}
163
164      ulunquote_cmd (qcmd);
165      return TRUE;
166    }
167
168  z = strtok ((char *) NULL, " \t\n");
169  if (z == NULL)
170    return FALSE;
171  qcmd->ztemp = z;
172
173  z = strtok ((char *) NULL, " \t\n");
174  if (z == NULL)
175    return FALSE;
176  qcmd->imode = (int) strtol (z, &zend, 0);
177  if (*zend != '\0')
178    return FALSE;
179
180  /* As a magic special case, if the mode came out as the decimal
181     values 666 or 777, assume that they actually meant the octal
182     values.  Most systems use a leading zero, but a few do not.
183     Since both 666 and 777 are greater than the largest legal mode
184     value, which is 0777 == 511, this hack does not restrict any
185     legal values.  */
186  if (qcmd->imode == 666)
187    qcmd->imode = 0666;
188  else if (qcmd->imode == 777)
189    qcmd->imode = 0777;
190
191  z = strtok ((char *) NULL, " \t\n");
192  if (qcmd->bcmd == 'E' && z == NULL)
193    return FALSE;
194  qcmd->znotify = z;
195
196  /* SVR4 UUCP will send the string "dummy" after the notify string
197     but before the size.  I do not know when it sends anything other
198     than "dummy".  Fortunately, it doesn't really hurt to not get the
199     file size.  */
200  if (z != NULL && strcmp (z, "dummy") == 0)
201    z = strtok ((char *) NULL, " \t\n");
202
203  if (z != NULL)
204    {
205      z = strtok ((char *) NULL, " \t\n");
206      if (z != NULL)
207	{
208	  qcmd->cbytes = strtol (z, &zend, 0);
209	  if (*zend != '\0')
210	    qcmd->cbytes = -1;
211	}
212      else if (qcmd->bcmd == 'E')
213	return FALSE;
214
215      if (z != NULL)
216	{
217	  z = strtok ((char *) NULL, "");
218	  if (z != NULL)
219	    z[strcspn (z, "\n")] = '\0';
220	  if (qcmd->bcmd == 'E' && z == NULL)
221	    return FALSE;
222	  qcmd->zcmd = z;
223	}
224    }
225
226  ulunquote_cmd (qcmd);
227
228  return TRUE;
229}
230
231/* If 'q' appears in the options of a command, unquote all the
232   relevant strings.  */
233
234static void
235ulunquote_cmd (qcmd)
236     struct scmd *qcmd;
237{
238  if (qcmd->zoptions == NULL || strchr (qcmd->zoptions, 'q') == NULL)
239    return;
240
241  if (qcmd->zfrom != NULL)
242    (void) cescape ((char *) qcmd->zfrom);
243  if (qcmd->zto != NULL)
244    (void) cescape ((char *) qcmd->zto);
245  if (qcmd->zuser != NULL)
246    (void) cescape ((char *) qcmd->zuser);
247  if (qcmd->znotify != NULL)
248    (void) cescape ((char *) qcmd->znotify);
249  if (qcmd->zcmd != NULL)
250    (void) cescape ((char *) qcmd->zcmd);
251}
252