comparison cmd.c @ 11:85bce13237cf

Add filter expressions to list command Refactor field parsing so it can be used for parsing fields, field assignments and filter expressions.
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Mon, 31 Jul 2017 09:20:21 +0200
parents 17fb30016e64
children 8768fbd09bc5
comparison
equal deleted inserted replaced
10:17fb30016e64 11:85bce13237cf
29 #include <errno.h> 29 #include <errno.h>
30 #include <limits.h> 30 #include <limits.h>
31 #ifdef HAVE_READPASSPHRASE_H 31 #ifdef HAVE_READPASSPHRASE_H
32 #include <readpassphrase.h> 32 #include <readpassphrase.h>
33 #endif /* READPASSPHRASE_H */ 33 #endif /* READPASSPHRASE_H */
34 #include <regex.h>
34 #include <stdlib.h> 35 #include <stdlib.h>
35 #include <string.h> 36 #include <string.h>
36 #include <time.h> 37 #include <time.h>
37 #include <unistd.h> 38 #include <unistd.h>
38 39
92 }; 93 };
93 94
94 static struct cmd cmds[] = { 95 static struct cmd cmds[] = {
95 { "i", "info", "info", "Show metadata information about the current file", 96 { "i", "info", "info", "Show metadata information about the current file",
96 cmd_info }, 97 cmd_info },
97 { "ls", "list", "list", "List entries", cmd_list }, 98 { "ls", "list", "list [field~regex ...]", "List entries", cmd_list },
98 { "c", "create", "create field=value ...", "Create entry", cmd_create }, 99 { "c", "create", "create field=value ...", "Create entry", cmd_create },
99 { "m", "modify", "modify id field=value ...", "Modify entry", cmd_modify }, 100 { "m", "modify", "modify id field=value ...", "Modify entry", cmd_modify },
100 { "rm", "remove", "remove id", "Delete entry", cmd_remove }, 101 { "rm", "remove", "remove id", "Delete entry", cmd_remove },
101 { "s", "show", "show id field", "Show entry", cmd_show }, 102 { "s", "show", "show id field", "Show entry", cmd_show },
102 { "p", "pipe", "pipe id field command", "Pipe entry to external command", 103 { "p", "pipe", "pipe id field command", "Pipe entry to external command",
112 { "q", "quit", "quit", "Quit", cmd_quit }, 113 { "q", "quit", "quit", "Quit", cmd_quit },
113 { 0 } 114 { 0 }
114 }; 115 };
115 116
116 static enum field_type 117 static enum field_type
117 parse_field_name(const char *name) 118 parse_field(char *field_arg, int sep, char **valuep)
118 {
119 int i;
120
121 for (i = 0; i < (int)COUNTOF(field_names); i++) {
122 if (strcmp(field_names[i], name) == 0) {
123 return (i);
124 }
125 }
126
127 return (FIELD_UNKNOWN);
128 }
129
130 static enum field_type
131 parse_field_assignment(char *arg, struct record *record)
132 { 119 {
133 int i; 120 int i;
134 size_t field_name_len; 121 size_t field_name_len;
135 char *value;
136 122
137 for (i = 0; i < (int)COUNTOF(field_names); i++) { 123 for (i = 0; i < (int)COUNTOF(field_names); i++) {
138 field_name_len = strlen(field_names[i]); 124 field_name_len = strlen(field_names[i]);
139 if ((strncmp(field_names[i], arg, field_name_len) == 0) && 125 if ((strncmp(field_names[i], field_arg, field_name_len) == 0) &&
140 (arg[field_name_len] == '=')){ 126 (field_arg[field_name_len] == sep)) {
141 value = arg + field_name_len + 1; 127 if (valuep != NULL) {
142 if (*value == '\0') { 128 *valuep = field_arg + field_name_len + 1;
143 /* skip empty assignments */
144 return (i);
145 }
146 switch (i) {
147 case FIELD_GROUP:
148 record->group = value;
149 break;
150 case FIELD_TITLE:
151 record->title = value;
152 break;
153 case FIELD_USERNAME:
154 record->username = value;
155 break;
156 case FIELD_PASSWORD:
157 record->password = value;
158 break;
159 case FIELD_NOTES:
160 record->notes = value;
161 break;
162 case FIELD_URL:
163 record->url = value;
164 break;
165 default:
166 return (FIELD_UNKNOWN);
167 } 129 }
168 return (i); 130 return (i);
169 } 131 }
170 } 132 }
171 133
221 } 183 }
222 184
223 static enum cmd_return 185 static enum cmd_return
224 cmd_list(struct pwm_ctx *ctx, int argc, char *argv[]) 186 cmd_list(struct pwm_ctx *ctx, int argc, char *argv[])
225 { 187 {
226 union list_item **list; 188 int retval = CMD_ERR;
227 size_t i; 189 int i;
228 190 regex_t *group_re = NULL;
229 if (argc != 1) { 191 regex_t *title_re = NULL;
230 return (CMD_USAGE); 192 regex_t *username_re = NULL;
193 regex_t *notes_re = NULL;
194 regex_t *url_re = NULL;
195 enum field_type type;
196 char *value;
197 regex_t **repp;
198 int errcode;
199 char *errbuf;
200 size_t errbuf_size;
201 union list_item **list = NULL;
202 size_t j;
203 struct record *record;
204
205 for (i = 1; i < argc; i++) {
206 type = parse_field(argv[i], '~', &value);
207 if (type == FIELD_UNKNOWN) {
208 fprintf(stderr, "bad field name \"%s\"\n", argv[i]);
209 goto out;
210 }
211 if (value[0] == '\0') {
212 /* skip empty expressions */
213 continue;
214 }
215 switch (type) {
216 case FIELD_GROUP:
217 repp = &group_re;
218 break;
219 case FIELD_TITLE:
220 repp = &title_re;
221 break;
222 case FIELD_USERNAME:
223 repp = &username_re;
224 break;
225 case FIELD_NOTES:
226 repp = &notes_re;
227 break;
228 case FIELD_URL:
229 repp = &url_re;
230 break;
231 default:
232 fprintf(stderr, "bad field name \"%s\"\n", argv[i]);
233 goto out;
234 }
235
236 if (*repp == NULL) {
237 *repp = xmalloc(sizeof (regex_t));
238 } else {
239 regfree(*repp);
240 }
241 errcode = regcomp(*repp, value, REG_EXTENDED | REG_NOSUB);
242 if (errcode != 0) {
243 errbuf_size = regerror(errcode, *repp, "", 0);
244 errbuf = xmalloc(errbuf_size);
245 regerror(errcode, *repp, errbuf, errbuf_size);
246 fprintf(stderr, "bad regular expression \"%s\"\n",
247 errbuf);
248 free(errbuf);
249
250 free(*repp);
251 *repp = NULL;
252
253 goto out;
254 }
231 } 255 }
232 256
233 list = pwfile_create_list(ctx); 257 list = pwfile_create_list(ctx);
234 for (i = 0; list[i] != NULL; i++) { 258 for (j = 0; list[j] != NULL; j++) {
235 if (list[i]->any.type == ITEM_TYPE_GROUP) { 259 if (list[j]->any.type == ITEM_TYPE_GROUP) {
236 printf("[%s]\n", list[i]->group.group); 260 printf("[%s]\n", list[j]->group.group);
237 } else { 261 } else {
238 printf("%4u %s\n", list[i]->record.id, 262 record = pwfile_get_record(ctx, list[j]->record.id);
239 (list[i]->record.title != NULL) ? 263 if (((group_re == NULL) || (regexec(group_re,
240 list[i]->record.title : ""); 264 record->group, 0, NULL, 0) == 0)) &&
241 } 265 ((title_re == NULL) || (regexec(title_re,
242 } 266 record->title, 0, NULL, 0) == 0)) &&
267 ((username_re == NULL) || (regexec(username_re,
268 record->username, 0, NULL, 0) == 0)) &&
269 ((notes_re == NULL) || (regexec(notes_re,
270 record->notes, 0, NULL, 0) == 0)) &&
271 ((url_re == NULL) || (regexec(url_re,
272 record->url, 0, NULL, 0) == 0))) {
273 printf("%4u %s\n", list[j]->record.id,
274 (list[j]->record.title != NULL) ?
275 list[j]->record.title : "");
276 }
277 pwfile_destroy_record(record);
278 }
279 }
280 retval = CMD_OK;
281
282 out:
283 if (group_re != NULL) {
284 regfree(group_re);
285 free(group_re);
286 }
287 if (title_re != NULL) {
288 regfree(title_re);
289 free(title_re);
290 }
291 if (username_re != NULL) {
292 regfree(username_re);
293 free(username_re);
294 }
295 if (notes_re != NULL) {
296 regfree(notes_re);
297 free(notes_re);
298 }
299 if (url_re != NULL) {
300 regfree(url_re);
301 free(url_re);
302 }
303
243 pwfile_destroy_list(list); 304 pwfile_destroy_list(list);
244 305
245 return (CMD_OK); 306 return (retval);
246 } 307 }
247 308
248 static enum cmd_return 309 static enum cmd_return
249 cmd_create(struct pwm_ctx *ctx, int argc, char *argv[]) 310 cmd_create(struct pwm_ctx *ctx, int argc, char *argv[])
250 { 311 {
251 int i; 312 int i;
252 struct record record = { 0 }; 313 struct record record = { 0 };
314 enum field_type type;
315 char *value;
253 316
254 if (argc < 2) { 317 if (argc < 2) {
255 return (CMD_USAGE); 318 return (CMD_USAGE);
256 } 319 }
257 320
258 for (i = 1; i < argc; i++) { 321 for (i = 1; i < argc; i++) {
259 if (parse_field_assignment(argv[i], &record) == FIELD_UNKNOWN) { 322 type = parse_field(argv[i], '=', &value);
323 if (type == FIELD_UNKNOWN) {
324 fprintf(stderr, "bad field assignment \"%s\"\n",
325 argv[i]);
326 }
327 if (value[0] == '\0') {
328 /* skip empty assignments */
329 continue;
330 }
331 switch (type) {
332 case FIELD_GROUP:
333 record.group = value;
334 break;
335 case FIELD_TITLE:
336 record.title = value;
337 break;
338 case FIELD_USERNAME:
339 record.username = value;
340 break;
341 case FIELD_PASSWORD:
342 record.password = value;
343 break;
344 case FIELD_NOTES:
345 record.notes = value;
346 break;
347 case FIELD_URL:
348 record.url = value;
349 break;
350 default:
351 fprintf(stderr, "bad field name \"%s\"\n", argv[i]);
352 return (CMD_ERR);
353 }
354 }
355
356 pwfile_create_record(ctx, &record);
357
358 return (CMD_OK);
359 }
360
361 static enum cmd_return
362 cmd_modify(struct pwm_ctx *ctx, int argc, char *argv[])
363 {
364 unsigned int id;
365 int i;
366 struct record record = { 0 };
367 enum field_type type;
368 char *value;
369
370 if (argc < 2) {
371 return (CMD_USAGE);
372 }
373
374 if (parse_id(argv[1], &id) != 0) {
375 fprintf(stderr, "invalid id %s\n", argv[1]);
376 return (CMD_ERR);
377 }
378
379 for (i = 2; i < argc; i++) {
380 type = parse_field(argv[i], '=', &value);
381 if (type == FIELD_UNKNOWN) {
260 fprintf(stderr, "bad field assignment \"%s\"\n", 382 fprintf(stderr, "bad field assignment \"%s\"\n",
261 argv[i]); 383 argv[i]);
262 return (CMD_ERR); 384 return (CMD_ERR);
263 } 385 }
264 } 386 if (value[0] == '\0') {
265 387 /* skip empty assignments */
266 pwfile_create_record(ctx, &record); 388 continue;
267 389 }
268 return (CMD_OK); 390 switch (type) {
269 } 391 case FIELD_GROUP:
270 392 record.group = value;
271 static enum cmd_return 393 break;
272 cmd_modify(struct pwm_ctx *ctx, int argc, char *argv[]) 394 case FIELD_TITLE:
273 { 395 record.title = value;
274 unsigned int id; 396 break;
275 int i; 397 case FIELD_USERNAME:
276 struct record record = { 0 }; 398 record.username = value;
277 399 break;
278 if (argc < 2) { 400 case FIELD_PASSWORD:
279 return (CMD_USAGE); 401 record.password = value;
280 } 402 break;
281 403 case FIELD_NOTES:
282 if (parse_id(argv[1], &id) != 0) { 404 record.notes = value;
283 fprintf(stderr, "invalid id %s\n", argv[1]); 405 break;
284 return (CMD_ERR); 406 case FIELD_URL:
285 } 407 record.url = value;
286 408 break;
287 for (i = 2; i < argc; i++) { 409 default:
288 if (parse_field_assignment(argv[i], &record) == FIELD_UNKNOWN) { 410 fprintf(stderr, "bad field name \"%s\"\n", argv[i]);
289 fprintf(stderr, "bad field assignment \"%s\"\n",
290 argv[i]);
291 return (CMD_ERR); 411 return (CMD_ERR);
292 } 412 }
293 } 413 }
294 414
295 pwfile_modify_record(ctx, id, &record); 415 pwfile_modify_record(ctx, id, &record);
408 fprintf(stderr, "invalid id %s\n", argv[1]); 528 fprintf(stderr, "invalid id %s\n", argv[1]);
409 return (CMD_ERR); 529 return (CMD_ERR);
410 } 530 }
411 531
412 for (i = 2; i < argc; i++) { 532 for (i = 2; i < argc; i++) {
413 type = parse_field_name(argv[i]); 533 type = parse_field(argv[i], '\0', NULL);
414 if (type < 0) { 534 if (type < 0) {
415 fprintf(stderr, "bad field name \"%s\"\n", argv[i]); 535 fprintf(stderr, "bad field name \"%s\"\n", argv[i]);
416 return (CMD_ERR); 536 return (CMD_ERR);
417 } 537 }
418 fields[type] = 1; 538 fields[type] = 1;
446 if (parse_id(argv[1], &id) != 0) { 566 if (parse_id(argv[1], &id) != 0) {
447 fprintf(stderr, "invalid id %s\n", argv[1]); 567 fprintf(stderr, "invalid id %s\n", argv[1]);
448 return (CMD_ERR); 568 return (CMD_ERR);
449 } 569 }
450 570
451 type = parse_field_name(argv[2]); 571 type = parse_field(argv[2], '\0', NULL);
452 if (type < 0) { 572 if (type < 0) {
453 fprintf(stderr, "bad field name \"%s\"\n", argv[2]); 573 fprintf(stderr, "bad field name \"%s\"\n", argv[2]);
454 return (CMD_ERR); 574 return (CMD_ERR);
455 } 575 }
456 fields[type] = 1; 576 fields[type] = 1;