From b843dec3932b5904af4a019f75d05ba8e0bdf191 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Mon, 5 Apr 2021 22:25:05 +0200 Subject: m + add set-contact-addresses + use -n instead of -l for country MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 5 +- TODO | 4 +- common-address.c | 32 +++--- common.h | 2 +- find-contact-by-address.c | 12 +-- get-contact-addresses.c | 16 +-- set-contact-addresses.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 281 insertions(+), 34 deletions(-) create mode 100644 set-contact-addresses.c diff --git a/Makefile b/Makefile index 3daf44f..2e3cb7f 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,7 @@ BIN =\ list-organisation-contacts\ print-contact\ remove-contact\ + set-contact-addresses\ set-contact-birthday\ set-contact-chats\ set-contact-emails\ @@ -188,8 +189,8 @@ print-contact: print-contact.o remove-contact: remove-contact.o $(CC) -o $@ $@.o $(LDFLAGS) -set-contact-addresses: set-contact-addresses.o - $(CC) -o $@ $@.o $(LDFLAGS) +set-contact-addresses: set-contact-addresses.o common-address.o + $(CC) -o $@ $@.o common-address.o $(LDFLAGS) set-contact-birthday: set-contact-birthday.o $(CC) -o $@ $@.o $(LDFLAGS) diff --git a/TODO b/TODO index 2cb5755..72da3fc 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,6 @@ Add tools for checking context for contact info Add tools for .blocks -set-contact-addresses - Test find-contact-by-chat Test find-contact-by-email Test find-contact-by-number @@ -31,6 +29,8 @@ Test set-contact-organisations Test set-contact-pgpkeys Test set-contact-photos Test set-contact-sites +Add ability to filter on unset values in entries +Add ability to remove values in entries Add man pages Add readme Add tests diff --git a/common-address.c b/common-address.c index 8ad8712..2f66208 100644 --- a/common-address.c +++ b/common-address.c @@ -3,7 +3,7 @@ int -parse_coord(char *s, double *lat_min, double *lat_max, double *lon_min, double *lon_max) +parse_coord(char *s, double *lat, double *lat_min, double *lat_max, double *lon, double *lon_min, double *lon_max) { int withsign = 0, neg; long int tmp; @@ -12,6 +12,7 @@ parse_coord(char *s, double *lat_min, double *lat_max, double *lon_min, double * errno = 0; if (s[0] == ':') { + *lat = 0; *lat_min = -90; *lat_max = +90; } else { @@ -25,24 +26,24 @@ parse_coord(char *s, double *lat_min, double *lat_max, double *lon_min, double * if (errno || tmp > INT_MAX) return -1; } - *lat_min = (double)tmp; + *lat = (double)tmp; if (s[0] == '.') { for (s++; isdigit(*s); s++) { - *lat_min *= 10; - *lat_min += (double)(*s & 15); + *lat *= 10; + *lat += (double)(*s & 15); prec *= 10; } - *lat_min /= prec; + *lat /= prec; } if (!withsign && (s[0] == 'N' || s[0] == 'S')) { neg = s[0] == 'S'; s = &s[1]; } if (neg) - *lat_min = -*lat_min; + *lat = -*lat; prec = (1 / prec) / 2; - *lat_max = *lat_min + prec; - *lat_min -= prec; + *lat_min = *lat - prec; + *lat_max = *lat + prec; if (s[0] != ':') return -1; } @@ -50,6 +51,7 @@ parse_coord(char *s, double *lat_min, double *lat_max, double *lon_min, double * s = &s[1]; if (!s[0]) { + *lon = 0; *lon_min = -180; *lon_max = +180; } else { @@ -63,24 +65,24 @@ parse_coord(char *s, double *lat_min, double *lat_max, double *lon_min, double * if (errno || tmp > INT_MAX) return -1; } - *lon_min = (double)tmp; + *lon = (double)tmp; if (s[0] == '.') { for (s++; isdigit(*s); s++) { - *lon_min *= 10; - *lon_min += (double)(*s & 15); + *lon *= 10; + *lon += (double)(*s & 15); prec *= 10; } - *lon_min /= prec; + *lon /= prec; } if (!withsign && (s[0] == 'E' || s[0] == 'W')) { neg = s[0] == 'W'; s = &s[1]; } if (neg) - *lon_min = -*lon_min; + *lon = -*lon; prec = (1 / prec) / 2; - *lon_max = *lon_min + prec; - *lon_min -= prec; + *lon_min = *lon - prec; + *lon_max = *lon + prec; if (s[0]) return -1; } diff --git a/common.h b/common.h index 6993070..a230e55 100644 --- a/common.h +++ b/common.h @@ -24,4 +24,4 @@ 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(char *s, double *lat_min, double *lat_max, double *lon_min, double *lon_max); +int parse_coord(char *s, double *lat, double *lat_min, double *lat_max, double *lon, double *lon_min, double *lon_max); diff --git a/find-contact-by-address.c b/find-contact-by-address.c index 646d0d5..b556e0f 100644 --- a/find-contact-by-address.c +++ b/find-contact-by-address.c @@ -1,19 +1,19 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -USAGE("[-a address] [-c context] [-g [latitude]:[longitude]] [-l country] [-o care-of] [-p post-code] [-t city]"); +USAGE("[-a address] [-c context] [-g [latitude]:[longitude]] [-n country] [-o care-of] [-p post-code] [-t city]"); int main(int argc, char *argv[]) { - struct passwd *user; - struct libcontacts_contact **contacts; - struct libcontacts_address **addresses, *addr; char *lookup_addr = NULL, *lookup_ctx = NULL, *lookup_loc = NULL; char *lookup_country = NULL, *lookup_careof = NULL; char *lookup_postcode = NULL, *lookup_city = NULL; double lat, lon, lat_min = 0, lat_max = 0, lon_min = 0, lon_max = 0; + struct passwd *user; + struct libcontacts_contact **contacts; + struct libcontacts_address **addresses, *addr; size_t i; ARGBEGIN { @@ -42,7 +42,7 @@ main(int argc, char *argv[]) usage(); lookup_city = ARG(); break; - case 'l': + case 'n': if (lookup_country) usage(); lookup_country = ARG(); @@ -51,7 +51,7 @@ main(int argc, char *argv[]) if (lookup_loc) usage(); lookup_loc = ARG(); - if (parse_coord(lookup_loc, &lat_min, &lat_max, &lon_min, &lon_max)) + if (parse_coord(lookup_loc, &lat, &lat_min, &lat_max, &lon, &lon_min, &lon_max)) usage(); break; default: diff --git a/get-contact-addresses.c b/get-contact-addresses.c index 89b4707..f936a94 100644 --- a/get-contact-addresses.c +++ b/get-contact-addresses.c @@ -1,21 +1,21 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -USAGE("[-a address] [-c context] [-g [latitude]:[longitude]] [-l country] " - "[-o care-of] [-p post-code] [-t city] [-ACGLOPT] contact-id ..."); +USAGE("[-a address] [-c context] [-g [latitude]:[longitude]] [-n country] " + "[-o care-of] [-p post-code] [-t city] [-ACGNOPT] contact-id ..."); int main(int argc, char *argv[]) { int fields = 0; - struct passwd *user; - struct libcontacts_contact contact; - struct libcontacts_address **addresses, *addr; char *lookup_addr = NULL, *lookup_ctx = NULL, *lookup_loc = NULL; char *lookup_country = NULL, *lookup_careof = NULL; char *lookup_postcode = NULL, *lookup_city = NULL; double lat, lon, lat_min = 0, lat_max = 0, lon_min = 0, lon_max = 0; + struct passwd *user; + struct libcontacts_contact contact; + struct libcontacts_address **addresses, *addr; int ret = 0, f; size_t i; @@ -45,7 +45,7 @@ main(int argc, char *argv[]) usage(); lookup_city = ARG(); break; - case 'l': + case 'n': if (lookup_country) usage(); lookup_country = ARG(); @@ -54,7 +54,7 @@ main(int argc, char *argv[]) if (lookup_loc) usage(); lookup_loc = ARG(); - if (parse_coord(lookup_loc, &lat_min, &lat_max, &lon_min, &lon_max)) + if (parse_coord(lookup_loc, &lat, &lat_min, &lat_max, &lon, &lon_min, &lon_max)) usage(); break; case 'C': @@ -72,7 +72,7 @@ main(int argc, char *argv[]) case 'T': fields |= 0x10; break; - case 'L': + case 'N': fields |= 0x20; break; case 'G': diff --git a/set-contact-addresses.c b/set-contact-addresses.c new file mode 100644 index 0000000..4d81c41 --- /dev/null +++ b/set-contact-addresses.c @@ -0,0 +1,244 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-a address | -A address] [-c context | -C context] [-g [latitude]:[longitude] | -G latitude:longitude] " + "[-n country | -N country] [-o care-of | -O care-of] [-p post-code | -P post-code] [-t city | -T city] " + "[-u] contact-id"); + + +static int +size_t_cmp(const void *av, const void *bv) +{ + const size_t *ap = av, *bp = bv; + return *ap < *bp ? -1 : *ap > *bp; +} + +int +main(int argc, char *argv[]) +{ + int edit_address = 0, edit_context = 0, edit_location = 0; + int edit_country = 0, edit_careof = 0, edit_postcode = 0; + int edit_city = 0, edit = 0, remove = 0; + char *address = NULL, *context = NULL, *location = NULL; + char *country = NULL, *careof = NULL, *postcode = NULL, *city = NULL; + double lat, lon, lat_min = 0, lat_max = 0, lon_min = 0, lon_max = 0, flat, flon; + struct passwd *user; + struct libcontacts_contact contact; + size_t i, *indices = NULL, nindices, naddresses; + char *p; + + ARGBEGIN { + case 'C': + edit_context = 1; + edit = 1; + /* fall through */ + case 'c': + if (context) + usage(); + context = ARG(); + break; + case 'O': + edit_careof = 1; + edit = 1; + /* fall through */ + case 'o': + if (careof) + usage(); + careof = ARG(); + break; + case 'A': + edit_address = 1; + edit = 1; + /* fall through */ + case 'a': + if (address) + usage(); + address = ARG(); + break; + case 'P': + edit_postcode = 1; + edit = 1; + /* fall through */ + case 'p': + if (postcode) + usage(); + postcode = ARG(); + break; + case 'T': + edit_city = 1; + edit = 1; + /* fall through */ + case 't': + if (city) + usage(); + city = ARG(); + break; + case 'N': + edit_country = 1; + edit = 1; + /* fall through */ + case 'n': + if (country) + usage(); + country = ARG(); + break; + case 'G': + edit_location = 1; + edit = 1; + /* fall through */ + case 'g': + if (location) + usage(); + location = ARG(); + if (edit_location) { + p = strchr(location, ':'); + if (!p || !p[1] || p == location) + usage(); + } + if (parse_coord(location, &lat, &lat_min, &lat_max, &lon, &lon_min, &lon_max)) + usage(); + break; + case 'u': + remove = 1; + break; + default: + usage(); + } ARGEND; + + if (remove == edit) { + if (edit) + eprintf("-u cannot be combined with -ACGLOPT\n"); + eprintf("at least one of -ACGLOPTu is required\n"); + } + + if ((!context || edit_context) && (!careof || edit_careof) && + (!address || edit_address) && (!postcode || edit_postcode) && + (!city || edit_city) && (!country || edit_country) && + (!location || edit_location)) + edit = 0; + + if (argc != 1 || !*argv[0] || strchr(argv[0], '/')) + usage(); + + 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"); + + naddresses = 0; + if (contact.addresses) + for (; contact.addresses[naddresses]; naddresses++); + + if ((edit || remove) && naddresses) { + nindices = naddresses; + indices = emalloc(nindices * sizeof(*contact.addresses)); + for (i = 0; i < nindices; i++) + indices[i] = i; + + if (context && !edit_context) + for (i = 0; i < nindices;) + if (strcmpnul(contact.addresses[indices[i++]]->context, context)) + indices[--i] = indices[--nindices]; + if (careof && !edit_careof) + for (i = 0; i < nindices;) + if (strcmpnul(contact.addresses[indices[i++]]->care_of, careof)) + indices[--i] = indices[--nindices]; + if (address && !edit_address) + for (i = 0; i < nindices;) + if (strcmpnul(contact.addresses[indices[i++]]->address, address)) + indices[--i] = indices[--nindices]; + if (postcode && !edit_postcode) + for (i = 0; i < nindices;) + if (strcmpnul(contact.addresses[indices[i++]]->postcode, postcode)) + indices[--i] = indices[--nindices]; + if (city && !edit_city) + for (i = 0; i < nindices;) + if (strcmpnul(contact.addresses[indices[i++]]->city, city)) + indices[--i] = indices[--nindices]; + if (country && !edit_country) + for (i = 0; i < nindices;) + if (strcmpnul(contact.addresses[indices[i++]]->country, country)) + indices[--i] = indices[--nindices]; + if (location && !edit_location) { + for (i = 0; i < nindices;) { + if (!contact.addresses[indices[i++]]->have_coordinates) { + flat = contact.addresses[indices[i - 1]]->latitude; + flon = contact.addresses[indices[i - 1]]->longitude; + if (!(lat_min <= flat && flat <= lat_max && lon_min <= flon && flon <= lon_max)) + indices[--i] = indices[--nindices]; + } + } + } + + if (edit) { + while (nindices--) { + i = indices[nindices]; + if (edit_context) { + free(contact.addresses[i]->context); + contact.addresses[i]->context = estrdup(context); + } + if (edit_careof) { + free(contact.addresses[i]->care_of); + contact.addresses[i]->care_of = estrdup(careof); + } + if (edit_address) { + free(contact.addresses[i]->address); + contact.addresses[i]->address = estrdup(address); + } + if (edit_postcode) { + free(contact.addresses[i]->postcode); + contact.addresses[i]->postcode = estrdup(postcode); + } + if (edit_city) { + free(contact.addresses[i]->city); + contact.addresses[i]->city = estrdup(city); + } + if (edit_country) { + free(contact.addresses[i]->country); + contact.addresses[i]->country = estrdup(country); + } + if (edit_location) { + contact.addresses[i]->latitude = lat; + contact.addresses[i]->longitude = lon; + contact.addresses[i]->have_coordinates = 1; + } + } + } else { + qsort(indices, nindices, sizeof(*indices), size_t_cmp); + while (nindices--) { /* reverse order is important */ + i = indices[nindices]; + libcontacts_address_destroy(contact.addresses[i]); + free(contact.addresses[i]); + /* we using memmove for simplity as we only expect to remove one entry */ + memmove(&contact.addresses[i], &contact.addresses[i + 1], + (naddresses-- - i) * sizeof(*contact.addresses)); + } + } + } else if (!edit && !remove) { + i = naddresses; + contact.addresses = erealloc(contact.addresses, (i + 2) * sizeof(*contact.addresses)); + contact.addresses[i + 1] = NULL; + contact.addresses[i] = ecalloc(1, sizeof(**contact.emails)); + contact.addresses[i]->context = context ? estrdup(context) : NULL; + contact.addresses[i]->care_of = careof ? estrdup(careof) : NULL; + contact.addresses[i]->address = address ? estrdup(address) : NULL; + contact.addresses[i]->postcode = postcode ? estrdup(postcode) : NULL; + contact.addresses[i]->city = city ? estrdup(city) : NULL; + contact.addresses[i]->country = country ? estrdup(country) : NULL; + if (location) { + contact.addresses[i]->have_coordinates = 1; + contact.addresses[i]->latitude = lat; + contact.addresses[i]->longitude = lon; + } + } + + if (libcontacts_save_contact(&contact, user)) + eprintf("libcontacts_save_contact %s:", argv[0]); + libcontacts_contact_destroy(&contact); + free(indices); + + return 0; +} -- cgit v1.2.3-70-g09d2