/* 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_SET_USAGE_UPPER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ "[-"UPPERS" old-"DISPLAY"] " #define X_SET_USAGE_LOWER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ "[-"LOWERS" new-"DISPLAY"] " #define X_SET_USAGE_BOOL(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ "[-"UPPERS" | -"LOWERS"] " #define X_SET_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ char *VAR = NULL, *lookup_##VAR = NULL, *old_##VAR = NULL; #define X_SET_BOOL_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ int set_##VAR = -1; #define X_SET_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_SET_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_SET_LOWER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ LOWERS #define X_SET_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (lookup_##VAR && strcmpnul(contact.CATEGORY[i]->VAR, lookup_##VAR))\ continue; #define X_SET_BOOL_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (remove && set_##VAR >= 0 && contact.CATEGORY[i]->is_##VAR != set_##VAR)\ continue; #define X_SET_CHANGE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (VAR) {\ old_##VAR = contact.CATEGORY[i]->VAR;\ contact.CATEGORY[i]->VAR = VAR;\ } #define X_SET_BOOL_SET(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (set_##VAR >= 0)\ contact.CATEGORY[i]->is_##VAR = set_##VAR; #define X_SET_ADD(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ contact.CATEGORY[i]->VAR = VAR; #define X_SET_RESTORE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ contact.CATEGORY[i]->VAR = old_##VAR; #define IMPLEMENT_SET_ON_LIST(CAT)\ USAGE(LIST_PARAMS(X_SET_USAGE_UPPER)LIST_BOOL_PARAMS(X_SET_USAGE_BOOL)"("LIST_PARAMS(X_SET_USAGE_LOWER)"| -u) contact-id");\ \ int\ main(int argc, char *argv[])\ {\ int add = 1, edit = 0, remove = 0;\ LIST_PARAMS(X_SET_PARAMS)\ LIST_BOOL_PARAMS(X_SET_BOOL_PARAMS)\ struct passwd *user;\ struct libcontacts_contact contact;\ struct libcontacts_##CAT **r = NULL, **w;\ size_t i;\ \ ARGBEGIN {\ LIST_PARAMS(X_SET_ARGPARSE)\ LIST_BOOL_PARAMS(X_SET_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_SET_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_SET_LOOKUP)\ LIST_BOOL_PARAMS(X_SET_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_SET_CHANGE)\ LIST_BOOL_PARAMS(X_SET_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_SET_ADD)\ LIST_BOOL_PARAMS(X_SET_BOOL_SET)\ }\ \ if (libcontacts_save_contact(&contact, user))\ eprintf("libcontacts_save_contact %s:", argv[0]);\ \ if (!r) {\ LIST_PARAMS(X_SET_RESTORE)\ }\ \ libcontacts_contact_destroy(&contact);\ return 0;\ } #define X_GET_USAGE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ "[-"LOWERS" "DISPLAY"] " #define X_GET_UPPER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ UPPERS #define X_GET_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ int display_##VAR = 0;\ const char *lookup_##VAR = NULL; #define X_GET_ARGPARSE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ case LOWERC:\ if (lookup_##VAR)\ usage();\ lookup_##VAR = ARG();\ break;\ case UPPERC:\ fields += !display_##VAR;\ display_##VAR = 1;\ break; #define X_GET_AUTO_DISPLAY(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ fields += display_##VAR = !lookup_##VAR; #define X_GET_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (lookup_##VAR && strcmpnul(elem->VAR, lookup_##VAR))\ continue; #define X_GET_FULL_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ lookup_##VAR && #define X_GET_DISPLAY(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\ if (display_##VAR) {\ fields_ -= 1;\ printf("%s%s", elem->VAR, fields_ ? ": " : "\n");\ } #define IMPLEMENT_GET_ON_LIST(CAT)\ USAGE(LIST_PARAMS(X_GET_USAGE)"[-"LIST_PARAMS(X_GET_UPPER)"] contact-id ..."); \ \ int\ main(int argc, char *argv[])\ {\ LIST_PARAMS(X_GET_PARAMS)\ struct passwd *user;\ struct libcontacts_contact contact;\ struct libcontacts_##CAT **elems, *elem;\ int ret = 0, fields = 0, fields_;\ size_t i; \ \ ARGBEGIN {\ LIST_PARAMS(X_GET_ARGPARSE)\ default:\ usage();\ } ARGEND;\ \ if (!argc)\ usage();\ \ if (!fields) {\ LIST_PARAMS(X_GET_AUTO_DISPLAY)\ }\ \ for (i = 0; argv[i]; i++)\ if (!*argv[i] || strchr(argv[i], '/'))\ usage();\ \ errno = 0;\ user = getpwuid(getuid());\ if (!user)\ eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");\ \ for (; *argv; argv++) {\ if (libcontacts_load_contact(*argv, &contact, user)) {\ weprintf("libcontacts_load_contact %s: %s\n", *argv,\ errno ? strerror(errno) : "contact file is malformatted");\ ret = 1;\ continue;\ }\ if ((elems = contact.CATEGORY)) {\ for (; (elem = *elems); elems++) {\ LIST_PARAMS(X_GET_LOOKUP)\ if (LIST_PARAMS(X_GET_FULL_LOOKUP) !fields) {\ printf("%s\n", *argv);\ continue;\ }\ if (argc > 1)\ printf("%s: ", *argv);\ fields_ = fields;\ LIST_PARAMS(X_GET_DISPLAY)\ }\ }\ libcontacts_contact_destroy(&contact);\ }\ \ if (fflush(stdout) || ferror(stdout) || fclose(stdout))\ eprintf("printf:");\ return ret;\ } #define X_FIND_USAGE(LOWERC, LOWERS, VAR, DISPLAY)\ "[-"LOWERS" "DISPLAY"] " #define X_FIND_PARAMS(LOWERC, LOWERS, VAR, DISPLAY)\ const char *VAR = NULL; #define X_FIND_ARGPARSE(LOWERC, LOWERS, VAR, DISPLAY)\ case LOWERC:\ if (VAR)\ usage();\ VAR = ARG();\ break; #define X_FIND_LOOKUP(LOWERC, LOWERS, VAR, DISPLAY)\ if (VAR && strcmpnul(elem->VAR, VAR))\ continue; #ifdef SUBCATEGORY # define PRINT_PREFIX_LIST(DATUM)\ if (elem->SUBCATEGORY && !SUBCATEGORY)\ printf("%s (%s: %s)\n", contacts[i]->id, elem->SUBCATEGORY, elem->DATUM);\ else # define PRINT_PREFIX_LOOKUP(DATUM)\ if (elem->SUBCATEGORY && !SUBCATEGORY)\ printf("%s (%s)\n", contacts[i]->id, elem->SUBCATEGORY);\ else #else # define PRINT_PREFIX_LIST(DATUM) # define PRINT_PREFIX_LOOKUP(DATUM) #endif #define IMPLEMENT_FIND_ON_LIST(CAT, DATUM, DISPLAY)\ USAGE(LIST_PARAMS(X_FIND_USAGE)"(-L | "DISPLAY")");\ \ int\ main(int argc, char *argv[])\ {\ int list = 0;\ LIST_PARAMS(X_FIND_PARAMS)\ struct passwd *user;\ struct libcontacts_contact **contacts;\ struct libcontacts_##CAT **elems, *elem;\ size_t i;\ \ ARGBEGIN {\ LIST_PARAMS(X_FIND_ARGPARSE)\ case 'L':\ list = 1;\ break;\ default:\ usage();\ } ARGEND;\ \ if (argc != 1 - list)\ usage();\ \ errno = 0;\ user = getpwuid(getuid());\ if (!user)\ eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");\ \ if (libcontacts_load_contacts(&contacts, user, 1))\ eprintf("libcontacts_load_contacts:");\ for (i = 0; contacts[i]; i++) {\ if ((elems = contacts[i]->CATEGORY)) {\ for (; (elem = *elems); elems++) {\ if (!elem->DATUM)\ continue;\ LIST_PARAMS(X_FIND_LOOKUP)\ if (list) {\ PRINT_PREFIX_LIST(DATUM)\ printf("%s (%s)\n", contacts[i]->id, elem->DATUM);\ } else if (!strcmp(elem->DATUM, argv[0])) {\ PRINT_PREFIX_LOOKUP(DATUM)\ printf("%s\n", contacts[i]->id);\ }\ }\ }\ libcontacts_contact_destroy(contacts[i]);\ free(contacts[i]);\ }\ free(contacts);\ \ if (fflush(stdout) || ferror(stdout) || fclose(stdout))\ eprintf("printf:");\ \ return 0;\ }