/* See LICENSE file for copyright and license details. */ #ifdef MULTICALL_BINARY # define LIBSIMPLY_CONFIG_MULTICALL_BINARY #endif #include #include #include #include #ifndef BUFSIZ # define BUFSIZ 4096 #endif /* common-birthday.c */ #if defined(__GNUC__) || defined(__clang__) __attribute__((__pure__)) #endif int get_age(struct libcontacts_birthday *bday, const struct tm *now); void print_birthdate(struct libcontacts_birthday *bday, const struct tm *now); void print_birthday(struct libcontacts_birthday *bday, const struct tm *now); /* common-address.c */ int parse_coord(const char *s, double *lat, double *lat_min, double *lat_max, double *lon, double *lon_min, double *lon_max); #ifndef LIST_BOOL_PARAMS # define LIST_BOOL_PARAMS(X) #endif #define X_USAGE_UPPER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ "[-"UPPERS" old-"DISPLAY"] " #define X_USAGE_LOWER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ "[-"LOWERS" new-"DISPLAY"] " #define X_USAGE_BOOL(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ "[-"UPPERS" | -"LOWERS"] " #define X_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ char *VAR = NULL, *lookup_##VAR = NULL, *old_##VAR = NULL; #define X_BOOL_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ int set_##VAR = -1; #define X_ARGPARSE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ case UPPERC:\ add = 0;\ if (lookup_##VAR)\ usage();\ lookup_##VAR = ARG();\ break;\ case LOWERC:\ edit = 1;\ if (VAR)\ usage();\ VAR = ARG();\ break; #define X_BOOL_ARGPARSE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ case UPPERC:\ if (set_##VAR >= 0)\ usage();\ set_##VAR = 0;\ break;\ case LOWERC:\ if (set_##VAR >= 0)\ usage();\ set_##VAR = 1;\ break; #define X_LOWER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ LOWERS #define X_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (lookup_##VAR && strcmpnul(contact.CATEGORY[i]->VAR, lookup_##VAR))\ continue; #define X_BOOL_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (remove && set_##VAR >= 0 && contact.CATEGORY[i]->is_##VAR != set_##VAR)\ continue; #define X_CHANGE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (VAR) {\ old_##VAR = contact.CATEGORY[i]->VAR;\ contact.CATEGORY[i]->VAR = VAR;\ } #define X_BOOL_SET(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (set_##VAR >= 0)\ contact.CATEGORY[i]->is_##VAR = set_##VAR; #define X_ADD(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ contact.CATEGORY[i]->VAR = VAR; #define X_RESTORE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ contact.CATEGORY[i]->VAR = old_##VAR; #define IMPLEMENT_SET_ON_LIST(CAT)\ USAGE(LIST_PARAMS(X_USAGE_UPPER)LIST_BOOL_PARAMS(X_USAGE_BOOL)"("LIST_PARAMS(X_USAGE_LOWER)"| -u) contact-id");\ \ int\ main(int argc, char *argv[])\ {\ int add = 1, edit = 0, remove = 0;\ LIST_PARAMS(X_PARAMS)\ LIST_BOOL_PARAMS(X_BOOL_PARAMS)\ struct passwd *user;\ struct libcontacts_contact contact;\ struct libcontacts_##CAT **r = NULL, **w;\ size_t i;\ \ ARGBEGIN {\ LIST_PARAMS(X_ARGPARSE)\ LIST_BOOL_PARAMS(X_BOOL_ARGPARSE)\ case 'u':\ remove = 1;\ break;\ default:\ usage();\ } ARGEND;\ \ if (argc != 1 || !*argv[0] || strchr(argv[0], '/'))\ usage();\ \ if (remove == edit) {\ if (edit)\ usage();\ eprintf("at least one of -"LIST_PARAMS(X_LOWER)"u is required\n");\ }\ \ if (add)\ edit = 0;\ \ errno = 0;\ user = getpwuid(getuid());\ if (!user)\ eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");\ \ if (libcontacts_load_contact(argv[0], &contact, user)) {\ eprintf("libcontacts_load_contact %s: %s\n", argv[0],\ errno ? strerror(errno) : "contact file is malformatted");\ }\ \ i = 0;\ if ((edit || remove) && contact.CATEGORY) {\ for (; contact.CATEGORY[i]; i++) {\ LIST_PARAMS(X_LOOKUP)\ LIST_BOOL_PARAMS(X_BOOL_LOOKUP)\ break;\ }\ if (!contact.CATEGORY[i]) {\ libcontacts_contact_destroy(&contact);\ return 0;\ } else if (!edit) {\ r = &contact.CATEGORY[i];\ libcontacts_##CAT##_destroy(*r);\ free(*r);\ for (w = r++; (*w++ = *r++););\ } else {\ LIST_PARAMS(X_CHANGE)\ LIST_BOOL_PARAMS(X_BOOL_SET)\ }\ } else if (!edit && !remove) {\ if (contact.CATEGORY)\ for (; contact.CATEGORY[i]; i++);\ contact.CATEGORY = erealloc(contact.CATEGORY, (i + 2) * sizeof(*contact.CATEGORY));\ contact.CATEGORY[i + 1] = NULL;\ contact.CATEGORY[i] = ecalloc(1, sizeof(**contact.CATEGORY));\ LIST_PARAMS(X_ADD)\ LIST_BOOL_PARAMS(X_BOOL_SET)\ }\ \ if (libcontacts_save_contact(&contact, user))\ eprintf("libcontacts_save_contact %s:", argv[0]);\ \ if (!r) {\ LIST_PARAMS(X_RESTORE)\ }\ \ libcontacts_contact_destroy(&contact);\ return 0;\ }