aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--TODO4
-rw-r--r--common-address.c32
-rw-r--r--common.h2
-rw-r--r--find-contact-by-address.c12
-rw-r--r--get-contact-addresses.c16
-rw-r--r--set-contact-addresses.c244
7 files changed, 281 insertions, 34 deletions
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;
+}