gawk

Sed-like interface to the Gopher protocol
git clone git://jacobedwards.org/gawk
Log | Files | Refs | LICENSE

command.c (6090B)


      1 /* Copyright 2021 Jacob R. Edwards
      2  *
      3  * This file is part of gawk.
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include <errno.h>
     20 #include <libgen.h>
     21 #include <limits.h>
     22 #include <string.h>
     23 #include <unistd.h>
     24 
     25 #include "gawk.h"
     26 #include "net.h"
     27 #include "util.h"
     28 
     29 /*
     30  * NOTE: The second and last parameters of the commands should at
     31  * every level (of pointers) be treated as immutable.
     32  *
     33  * TODO: Figure out why `char **` -> `char const **` and the like
     34  * causes warnings and, if possible, make the second and last
     35  * parameters of commands truely immutable.
     36  */
     37 
     38 #define LOCAL	/* functions local to this file */
     39 
     40 char **
     41 itemtoaddr(char **request)
     42 {
     43         return request + 1;
     44 }
     45 
     46 LOCAL int
     47 type(int c, char const *types, int want)
     48 {
     49 	if (strchr(types, c) != NULL)
     50 		return !want;
     51 	else	return  want;
     52 }
     53 
     54 LOCAL int
     55 wtype(char const *argv0, int c, char const *types, int want)
     56 {
     57 	if (type(c, types, want) == 1) {
     58 		warn(0, "%s: '%c': Invalid type", argv0, c);
     59 		return 1;
     60 	}
     61 	return 0;
     62 }
     63 
     64 LOCAL int
     65 warg(int min, int max, int argc, char **ap)
     66 {
     67 	if (max > 0 && argc > max)
     68 		warn(0, "%s: '%s'... unused", *ap, ap[max]);
     69 	else if (min > 0 && argc < min)
     70 		warn(0, "%s: Not enough arguments", *ap);
     71 	else
     72 		return 0;
     73 	return 1;
     74 }
     75 
     76 int
     77 cextern(int argc, char **argv, int ino, char **item)
     78 {
     79 	char url[MY_URL_MAX];
     80 	int i;
     81 
     82 	if (warg(2, -1, argc, argv))
     83 		return FAIL;
     84 
     85 	snprintf(url, sizeof(url), "%s%s", item[GI_HOST], item[GI_PATH]);
     86 	for (i = 1; i < argc; ++i)
     87 		if (strcmp(argv[i], "%") == 0)
     88 			argv[i] = url;
     89 
     90 	switch (fork()) {
     91 	case -1:
     92 		warn(errno, "unable to fork");
     93 		return FAIL;
     94 	case 0:
     95 		++argv;
     96 		execvp(*argv, argv);
     97 		warn(errno, "execvp '%s'", *argv);
     98 		_exit(1);
     99 	}
    100 
    101 	return PASS;
    102 }
    103 
    104 LOCAL int
    105 timid_gopher(char **addr, char *path, int bin, int timeout)
    106 {
    107 	if (!exists(path))
    108 		return gopher(addr, path, bin, timeout);
    109 	warn(EEXIST, "not writing to '%s'", path);
    110 	return 1;
    111 }
    112 
    113 int
    114 cfetch(int argc, char **argv, int ino, char **item)
    115 {
    116 	char *path;
    117 	int bin;
    118 
    119 	if (warg(1, 2, argc, argv) || wtype(*argv, **item, "i3", 0))
    120 		return FAIL;
    121 
    122 	if (argv[1])
    123 		path = argv[1];
    124 	else {
    125 		path = basename(item[GI_PATH]);
    126 		if (path == NULL) {
    127 			warn(errno, "unable to get basename '%s'", item[GI_PATH]);
    128 			return NEXT;
    129 		}
    130 	}
    131 
    132 	bin = **item == '0' ? 0 : 1;
    133 	if (timid_gopher(itemtoaddr(item), path, bin, timeout))
    134 		return NEXT;
    135 	warn(0, "%s: '%s%s' > '%s'", *argv, item[GI_HOST], item[GI_PATH], path);
    136 	return PASS;
    137 }
    138 
    139 LOCAL int
    140 cgoto7(int argc, char **argv, int ino, char **item)
    141 {
    142 	char tmp[MY_PATH_MAX];
    143 
    144 	if (wtype(*argv, **item, "7", 1) || warg(2, 2, argc, argv))
    145 		return FAIL;
    146 
    147 	/* NOTE: the user inserts `?` for a space */
    148 	snprintf(tmp, sizeof(tmp), "%s?%s", item[GI_PATH], argv[1]);
    149 	item[GI_PATH] = tmp;
    150 	return gawk(itemtoaddr(item));
    151 }
    152 
    153 int
    154 cgoto(int argc, char **argv, int ino, char **item)
    155 {
    156 	if (**item == '1') {
    157 		if (warg(1, 1, argc, argv))
    158 			return FAIL;
    159 		return gawk(itemtoaddr(item));
    160 	}
    161 	return cgoto7(argc, argv, ino, item);
    162 }
    163 
    164 int
    165 cprint(int argc, char **argv, int ino, char **item)
    166 {
    167 	if (warg(1, 1, argc, argv))
    168 		return FAIL;
    169 
    170 	if (**item == 'i')
    171 		printf("  %s\n", item[GI_INFO] + 1);
    172 	else if (**item == '3')
    173 		fprintf(stderr, "%s: %s\n", item[GI_HOST], item[GI_INFO] + 1);
    174 	else
    175 		printf("%4d [%c] %s\n", ino, item[GI_INFO][0],
    176 		    item[GI_INFO] + 1);
    177 	return PASS;
    178 }
    179 
    180 int
    181 cprintv(int argc, char **argv, int ino, char **item)
    182 {
    183 	if (**item != 'i' && **item != '3')
    184 		printf("\n     %s%s\n", item[GI_HOST], item[GI_PATH]);
    185 	return cprint(argc, argv, ino, item);
    186 }
    187 
    188 int
    189 findex(int argc, char **argv, int ino, char **item)
    190 {
    191 	char const *err;
    192 	int i;
    193 	int n;
    194 
    195 	if (warg(2, -1, argc, argv))
    196 		return FAIL;
    197 
    198 	for (i = 1; i < argc; ++i) {
    199 		n = wstrtonum(argv[i], 0, INT_MAX, &err);
    200 		if (err != NULL)
    201 			return FAIL;
    202 		if (ino == n)
    203 			return PASS;
    204 	}
    205 	return NEXT;
    206 }
    207 
    208 int
    209 frange(int argc, char **argv, int ino, char **item)
    210 {
    211 	char const *err;
    212 	int i, j;
    213 	int range[2];
    214 
    215 	if (warg(3, -1, argc, argv))
    216 		return FAIL;
    217 	if (argc % 2 != 1) {
    218 		warn(0, "%s: Unbalenced range", *argv);
    219 		return FAIL;
    220 	}
    221 	
    222 	for (i = 1; i < argc; i += 2) {
    223 		for (j = 0; j < 2; ++j) {
    224 			range[j] = wstrtonum(argv[i + j], 0, INT_MAX, &err);
    225 			if (err != NULL)
    226 				return FAIL;
    227 		}
    228 		if (range[0] > range[1]) {
    229 			if (ino < range[1] || ino > range[0])
    230 				return NEXT;
    231 		} else if (ino < range[0] || ino > range[1])
    232 			return NEXT;
    233 	}
    234 
    235 	return PASS;
    236 }
    237 
    238 int
    239 fstring(int argc, char **argv, int ino, char **item)
    240 {
    241 	int i;
    242 
    243 	if (warg(2, -1, argc, argv))
    244 		return FAIL;
    245 	for (i = 1; i < argc; ++i)
    246 		if (strcasestr(item[GI_INFO], argv[1]) == NULL)
    247 			return NEXT;
    248 	return PASS;
    249 }
    250 
    251 int
    252 ftype(int argc, char **argv, int ino, char **item)
    253 {
    254 	if (warg(2, 2, argc, argv))
    255 	       return FAIL;
    256 	if (type(**item, argv[1], 0))
    257                return PASS;
    258 	return NEXT;
    259 }
    260 
    261 int
    262 sexit(int argc, char **argv, int depth, char **addr)
    263 {
    264 	if (warg(1, 1, argc, argv))
    265 		return FAIL;
    266 	return depth;
    267 }
    268 
    269 int
    270 sgoto(int argc, char **argv, int depth, char **addr)
    271 {
    272 	char *newaddr[AR_NULL];
    273 	int i;
    274 
    275 	if (warg(1, 4, argc, argv))
    276 		return FAIL;
    277 
    278 	newaddr[AR_HOST] = addr[AR_HOST];
    279 	newaddr[AR_PATH] = "/";
    280 	newaddr[AR_PORT] = addr[AR_PORT];
    281 
    282 	for (i = 1; i < argc; ++i)
    283 		newaddr[i - 1] = argv[i];
    284 	return gawk(newaddr);
    285 }
    286 
    287 int
    288 sunwind(int argc, char **argv, int depth, char **addr)
    289 {
    290 	char const *err;
    291 	int n;
    292 
    293 	if (warg(1, 2, argc, argv))
    294 		return FAIL;
    295 
    296 	if (argc == 1)
    297 		n = 1;
    298 	else {
    299 		n = wstrtonum(argv[1], 0, INT_MAX, &err);
    300 		if (err != NULL)
    301 			return FAIL;
    302 	}
    303 	return n;
    304 }