rohrpost

A commandline mail client to change the world as we see it.
git clone git://r-36.net/rohrpost
Log | Files | Refs | README | LICENSE

parser.c (6974B)


      1 /*
      2  * Copy me if you can.
      3  * by 20h
      4  */
      5 
      6 #include <unistd.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <strings.h>
     11 
     12 #include "ind.h"
     13 #include "net.h"
     14 #include "strio.h"
     15 #include "parser.h"
     16 #include "base64.h"
     17 
     18 enum {
     19 	PARSER_NET = 0x00,
     20 	PARSER_STRING
     21 };
     22 static char *parsernames[] = {
     23 	[PARSER_NET] = "net",
     24 	[PARSER_STRING] = "string"
     25 };
     26 
     27 parser_t *
     28 parser_new(char *type, void *struc)
     29 {
     30 	parser_t *ret;
     31 	int ttype, i;
     32 
     33 	for (i = 0, ttype = -1; i < nelem(parsernames); i++)
     34 		if (!strcmp(parsernames[i], type))
     35 			ttype = i;
     36 	if (ttype > -1) {
     37 		ret = mallocz(sizeof(parser_t), 2);
     38 		ret->type = ttype;
     39 		ret->types = memdup(type, strlen(type)+1);
     40 		ret->struc = struc;
     41 	} else
     42 		return NULL;
     43 	return ret;
     44 }
     45 
     46 void
     47 parser_free(parser_t *parser)
     48 {
     49 	if (parser->types != NULL)
     50 		free(parser->types);
     51 	free(parser);
     52 }
     53 
     54 int
     55 parser_read(parser_t *parser, char *buf, int len)
     56 {
     57 	//int r;
     58 
     59 	switch(parser->type) {
     60 	case PARSER_NET:
     61 		//r = net_read((net_t *)parser->struc, buf, len);
     62 		//printf(buf);
     63 		//return r;
     64 		return net_read((net_t *)parser->struc, buf, len);
     65 	case PARSER_STRING:
     66 		//r = strio_read((strio_t *)parser->struc, buf, len);
     67 		//printf(buf);
     68 		//return r;
     69 		return strio_read((strio_t *)parser->struc, buf, len);
     70 	default:
     71 		break;
     72 	}
     73 
     74 	return -1;
     75 }
     76 
     77 int
     78 parser_readall(parser_t *parser, char *buf, int len)
     79 {
     80 	//int r;
     81 
     82 	switch(parser->type) {
     83 	case PARSER_NET:
     84 		//r = net_readall((net_t *)parser->struc, buf, len);
     85 		//printf(buf);
     86 		//return r;
     87 		return net_readall((net_t *)parser->struc, buf, len);
     88 	case PARSER_STRING:
     89 		//r = strio_readall((strio_t *)parser->struc, buf, len);
     90 		//printf(buf);
     91 		//return r;
     92 		return strio_readall((strio_t *)parser->struc, buf, len);
     93 	default:
     94 		break;
     95 	}
     96 
     97 	return -1;
     98 }
     99 
    100 char *
    101 parser_getuntil(parser_t *parser, void *str, int slen)
    102 {
    103 	char *ret;
    104 	int len, pos;
    105 
    106 	pos = 0;
    107 	len = 1;
    108 	ret = mallocz(len, 2);
    109 	while (parser_read(parser, &ret[len-1], 1) > 0 && len < MAXLINESIZE) {
    110 		if (ret[len-1] == ((char *)str)[pos]) {
    111 			pos++;
    112 			if (pos >= slen)
    113 				break;
    114 		} else
    115 			pos = 0;
    116 
    117 		ret = reallocz(ret, ++len + 1, 0);
    118 	}
    119 	ret[len] = '\0';
    120 
    121 	return ret;
    122 }
    123 
    124 char *
    125 parser_encodeplainlogin(char *user, char *pass)
    126 {
    127 	char *authstr, *b64a;
    128 	int len;
    129 
    130 	authstr = memdup("\0", 1);
    131 	len = 1;
    132 	authstr = memdupcat(authstr, len, user, strlen(user)+1);
    133 	len += strlen(user) + 1;
    134 	authstr = memdupcat(authstr, len, pass, strlen(pass)+1);
    135 	len += strlen(pass);
    136 	b64a = b64enc(authstr, len);
    137 	free(authstr);
    138 
    139 	return b64a;
    140 }
    141 
    142 char *
    143 parser_encodestring(char *str)
    144 {
    145 	if (strchr(str, '\n') || strchr(str, '\r') || strchr(str, '"'))
    146 		return smprintf("{%d+}\r\n%s", strlen(str), str);
    147 	else
    148 		return smprintf("\"%s\"", str);
    149 }
    150 
    151 char *
    152 parser_parsesieve(parser_t *parser, char *ptr)
    153 {
    154 	int len;
    155 	char *ret;
    156 
    157 	switch (ptr[0]) {
    158 	case '"':
    159 		sscanf(ptr+1, "%1024m[^\"]%*[^\n]", &ret);
    160 		break;
    161 	case '{':
    162 		sscanf(ptr, "{%d+}%*[^\n]", &len);
    163 		if (len > 0) {
    164 			ret = mallocz(len+1, 2);
    165 			parser_readall(parser, ret, len);
    166 		} else
    167 			return NULL;
    168 		break;
    169 	default:
    170 		sscanf(ptr, "%1024m[^ ]%*[^\n]", &ret);
    171 		break;
    172 	}
    173 
    174 	return ret;
    175 }
    176 
    177 char *
    178 parser_simplestring(char *str)
    179 {
    180 	char *ret;
    181 
    182 	switch (str[0]) {
    183 	case '"':
    184 		sscanf(str+1, "%1024m[^\"]%*[^\n]", &ret);
    185 		break;
    186 	default:
    187 		sscanf(str, "%1024m[^ ]%*[^\n]", &ret);
    188 		break;
    189 	}
    190 
    191 	return ret;
    192 }
    193 
    194 llist_t *
    195 parser_parseimapstructinternal(parser_t *parser, llist_t *ret)
    196 {
    197 	llist_t *res;
    198 	llistelem_t *lce, *pope;
    199 	char buf[1025], *dbuf, lc, cchar;
    200 	int i, len, incomment;
    201 
    202 	memset(buf, 0, sizeof(buf));
    203 
    204 parsestructagain:
    205 	i = 1;
    206 	if (parser_read(parser, buf, 1) <= 0)
    207 		return NULL;
    208 	//printf("%s", buf);
    209 	switch (buf[0]) {
    210 	case '{':
    211 		for (; parser_read(parser, &buf[i], 1) > 0 && i < sizeof(buf);
    212 				i++) {
    213 			if (buf[i] == '}')
    214 				break;
    215 		}
    216 		lc = buf[i];
    217 		buf[i] = '\0';
    218 
    219 		len = atoi(&buf[1]);
    220 
    221 		if (len < 1)
    222 			llist_add(ret, "nil", NULL, 0);
    223 		else {
    224 			dbuf = mallocz(len+1, 2);
    225 			parser_readall(parser, dbuf, 2);
    226 			parser_readall(parser, dbuf, len);
    227 			llist_add(ret, "literal", dbuf, len+1);
    228 		}
    229 		llist_add(ret, "lc", &lc, 1);
    230 		free(dbuf);
    231 		break;
    232 	case '"':
    233 		for (i = 0, incomment = 0; parser_read(parser, &buf[i], 1) > 0
    234 				&& i < sizeof(buf); i++) {
    235 			switch (buf[i]) {
    236 			case '"':
    237 				if (incomment)
    238 					break;
    239 				if (buf[i-1] == '\\') {
    240 					buf[i-1] = '"';
    241 					i--;
    242 				} else
    243 					goto parsestructend;
    244 				break;
    245 			case '\\':
    246 				if (buf[i-1] == '\\') {
    247 					buf[i-1] = '\\';
    248 					i--;
    249 				}
    250 				break;
    251 			case '(':
    252 			case '[':
    253 				if (!incomment) {
    254 					if (buf[i] == '(')
    255 						cchar = ')';
    256 					else
    257 						cchar = ']';
    258 					incomment = 1;
    259 				}
    260 				break;
    261 			case ')':
    262 			case ']':
    263 				if (cchar == buf[i] && incomment) {
    264 					incomment = 0;
    265 					break;
    266 				}
    267 				goto parsestructend;
    268 			default:
    269 				break;
    270 			}
    271 		}
    272 parsestructend:
    273 		lc = buf[i];
    274 		buf[i] = '\0';
    275 		llist_add(ret, "string", buf, strlen(buf)+1);
    276 		llist_add(ret, "lc", &lc, 1);
    277 		break;
    278 	case '(':
    279 		res = llist_new();
    280 		llist_addraw(ret, NULL, res, sizeof(res));
    281 		for(;;) {
    282 			res = llist_new();
    283 			if (parser_parseimapstructinternal(parser, res)
    284 					== NULL) {
    285 				llist_free(res);
    286 				break;
    287 			}
    288 			if (res->first->key != NULL &&
    289 					!strcmp(res->first->key, "listend")) {
    290 				llist_free(res);
    291 				break;
    292 			}
    293 
    294 			pope = llist_pop(res);
    295 			llist_addelem((llist_t *)ret->first->data, pope);
    296 
    297 			lce = llist_get(res, "lc");
    298 			if (lce != NULL) {
    299 				lc = ((char *)lce->data)[0];
    300 			} else
    301 				lc = '\0';
    302 			llist_efree(res);
    303 
    304 			if (lc == ')')
    305 				break;
    306 		}
    307 		break;
    308 	case '0':
    309 	case '1':
    310 	case '2':
    311 	case '3':
    312 	case '4':
    313 	case '5':
    314 	case '6':
    315 	case '7':
    316 	case '8':
    317 	case '9':
    318 		for (; parser_read(parser, &buf[i], 1) > 0 && i < sizeof(buf);
    319 				i++)
    320 			if (buf[i] > '9' || buf[i] < '0')
    321 				break;
    322 		lc = buf[i];
    323 		buf[i] = '\0';
    324 		llist_add(ret, "number", buf, strlen(buf)+1);
    325 		llist_add(ret, "lc", &lc, 1);
    326 		break;
    327 	case ' ':
    328 	case '\t':
    329 	case '\r':
    330 	case '\f':
    331 	case '\v':
    332 		goto parsestructagain;
    333 	case '\n':
    334 		return NULL;
    335 	case ')':
    336 		llist_add(ret, "listend", NULL, 0);
    337 		llist_add(ret, "lc", &lc, 1);
    338 		break;
    339 	default:
    340 		for (; parser_read(parser, &buf[i], 1) > 0 && i < sizeof(buf);
    341 				i++) {
    342 			switch (buf[i]) {
    343 			case ' ':
    344 			case '\t':
    345 			case '\r':
    346 			case '\n':
    347 			case '"':
    348 			case ')':
    349 				goto atomshouldstop;
    350 			default:
    351 				break;
    352 			};
    353 		}
    354 atomshouldstop:
    355 		lc = buf[i];
    356 		buf[i] = '\0';
    357 		if (!strcmp(buf, "NIL"))
    358 			llist_add(ret, "nil", NULL, 0);
    359 		else
    360 			llist_add(ret, "atom", buf, strlen(buf)+1);
    361 		llist_add(ret, "lc", &lc, 1);
    362 		break;
    363 	}
    364 
    365 	return ret;
    366 }
    367 
    368 llistelem_t *
    369 parser_parseimapstruct(parser_t *parser)
    370 {
    371 	llist_t *res;
    372 	llistelem_t *ret;
    373 
    374 	res = llist_new();
    375 	if (parser_parseimapstructinternal(parser, res) == NULL) {
    376 		llist_efree(res);
    377 		return NULL;
    378 	}
    379 	if (res->len < 1) {
    380 		llist_efree(res);
    381 		return NULL;
    382 	}
    383 
    384 	if (res->first->key != NULL && !strcmp(res->first->key, "listend")) {
    385 		llist_efree(res);
    386 		return NULL;
    387 	}
    388 
    389 	ret = llist_pop(res);
    390 	llist_efree(res);
    391 
    392 
    393 	return ret;
    394 }
    395