Mercurial > projects > pwm
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 = ¬es_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; |