aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-04-03 02:28:44 +0200
committerMattias Andrée <maandree@kth.se>2021-04-03 02:28:44 +0200
commit49e4bd18d29d5ef9c85d106026b09d86de6ff19c (patch)
treeacaad00d8d6df3a9dd6f0780fb837933b6ccddfd
downloadcontacts-49e4bd18d29d5ef9c85d106026b09d86de6ff19c.tar.gz
contacts-49e4bd18d29d5ef9c85d106026b09d86de6ff19c.tar.bz2
contacts-49e4bd18d29d5ef9c85d106026b09d86de6ff19c.tar.xz
First commmit
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--.gitignore32
-rw-r--r--LICENSE15
-rw-r--r--Makefile132
-rw-r--r--TODO30
-rw-r--r--common.h4
-rw-r--r--config.mk8
-rw-r--r--find-contact-by-email.c62
-rw-r--r--find-contact-by-name.c74
-rw-r--r--find-contact-by-pgpkey.c62
-rw-r--r--find-contact-by-site.c62
-rw-r--r--get-contact-emails.c86
-rw-r--r--get-contact-file.c34
-rw-r--r--get-contact-gender.c57
-rw-r--r--get-contact-name.c74
-rw-r--r--get-contact-notes.c35
-rw-r--r--get-contact-organisations.c86
-rw-r--r--get-contact-pgpkeys.c86
-rw-r--r--get-contact-sites.c86
-rw-r--r--is-contact-ice.c41
-rw-r--r--list-contacts.c84
-rw-r--r--set-contact-emails.c105
-rw-r--r--set-contact-gender.c71
-rw-r--r--set-contact-ice.c50
-rw-r--r--set-contact-name.c72
-rw-r--r--set-contact-notes.c62
-rw-r--r--set-contact-organisations.c106
-rw-r--r--set-contact-pgpkeys.c105
-rw-r--r--set-contact-sites.c105
28 files changed, 1826 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fb34b0a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+*\#*
+*~
+*.o
+*.a
+*.so
+*.so.*
+*.su
+*.lo
+/find-contact-by-email
+/find-contact-by-name
+/find-contact-by-pgpkey
+/find-contact-by-site
+/get-contact-emails
+/get-contact-file
+/get-contact-gender
+/get-contact-name
+/get-contact-notes
+/get-contact-organisations
+/get-contact-pgpkeys
+/get-contact-sites
+/is-contact-ice
+/list-contact-organisations
+/list-contacts
+/list-organisation-contacts
+/set-contact-emails
+/set-contact-gender
+/set-contact-ice
+/set-contact-name
+/set-contact-notes
+/set-contact-organisations
+/set-contact-pgpkeys
+/set-contact-sites
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c44b2d9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+© 2021 Mattias Andrée <maandree@kth.se>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..86040fa
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,132 @@
+.POSIX:
+
+CONFIGFILE = config.mk
+include $(CONFIGFILE)
+
+
+BIN =\
+ find-contact-by-email\
+ find-contact-by-name\
+ find-contact-by-pgpkey\
+ find-contact-by-site\
+ get-contact-emails\
+ get-contact-file\
+ get-contact-gender\
+ get-contact-name\
+ get-contact-notes\
+ get-contact-organisations\
+ get-contact-pgpkeys\
+ get-contact-sites\
+ is-contact-ice\
+ list-contacts\
+ set-contact-emails\
+ set-contact-gender\
+ set-contact-ice\
+ set-contact-name\
+ set-contact-notes\
+ set-contact-organisations\
+ set-contact-pgpkeys\
+ set-contact-sites
+
+HDR =\
+ common.h
+
+OBJ = $(BIN:=.o)
+
+
+all: $(BIN)
+$(OBJ): $(@:.o=.c) $(HDR)
+
+libcontacts.a: $(OBJ)
+ $(AR) rc $@ $(OBJ)
+ $(AR) -s $@
+
+.c.o:
+ $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+find-contact-by-email: find-contact-by-email.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+find-contact-by-name: find-contact-by-name.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+find-contact-by-pgpkey: find-contact-by-pgpkey.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+find-contact-by-site: find-contact-by-site.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-emails: get-contact-emails.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-file: get-contact-file.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-gender: get-contact-gender.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-name: get-contact-name.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-notes: get-contact-notes.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-organisations: get-contact-organisations.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-pgpkeys: get-contact-pgpkeys.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+get-contact-sites: get-contact-sites.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+is-contact-ice: is-contact-ice.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+list-contact-organisations: list-contact-organisations.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+list-contacts: list-contacts.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+list-organisation-contacts: list-organisation-contacts.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-emails: set-contact-emails.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-gender: set-contact-gender.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-ice: set-contact-ice.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-name: set-contact-name.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-notes: set-contact-notes.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-organisations: set-contact-organisations.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-pgpkeys: set-contact-pgpkeys.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+set-contact-sites: set-contact-sites.o
+ $(CC) -o $@ $@.o $(LDFLAGS)
+
+install: $(BIN)
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/bin"
+ cp -- $(BIN) "$(DESTDIR)$(PREFIX)/bin/"
+
+uninstall:
+ -cd -- "$(DESTDIR)$(PREFIX)/bin" && rm -f -- $(BIN)
+
+clean:
+ -rm -f -- *.o *.a *.lo *.so *.su $(BIN)
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+.PHONY: all install uninstall clean
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..33d0025
--- /dev/null
+++ b/TODO
@@ -0,0 +1,30 @@
+list-contact-organisations
+list-organisation-contacts
+
+Add tools for .photos
+Add tools for .groups
+Add tools for .blocks
+Add tools for .numbers
+Add tools for .addresses
+Add tools for .chats
+Add tools for .birthday
+Test find-contact-by-email
+Test find-contact-by-name
+Test find-contact-by-pgpkey
+Test find-contact-by-site
+Test get-contact-emails
+Test get-contact-name
+Test get-contact-organisations
+Test get-contact-pgpkeys
+Test get-contact-sites
+Test list-contact-organisations
+Test list-organisation-contacts
+Test set-contact-emails
+Test set-contact-name
+Test set-contact-organisations
+Test set-contact-pgpkeys
+Test set-contact-sites
+Add man pages
+Add readme
+Add tests
+Add multicall binary
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..14c3319
--- /dev/null
+++ b/common.h
@@ -0,0 +1,4 @@
+/* See LICENSE file for copyright and license details. */
+#include "libcontacts.h"
+#include "libsimple.h"
+#include "libsimple-arg.h"
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..34514f2
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,8 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CC = cc
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700
+CFLAGS = -std=c99 -Wall -O2
+LDFLAGS = -s -lcontacts -lsimple
diff --git a/find-contact-by-email.c b/find-contact-by-email.c
new file mode 100644
index 0000000..cff71db
--- /dev/null
+++ b/find-contact-by-email.c
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-c context] (-L | address)");
+
+
+int
+main(int argc, char *argv[])
+{
+ int list = 0;
+ struct passwd *user;
+ struct libcontacts_contact **contacts;
+ struct libcontacts_email **emails, *email;
+ char *context = NULL;
+ size_t i;
+
+ ARGBEGIN {
+ case 'c':
+ if (context)
+ usage();
+ context = ARG();
+ break;
+ 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))
+ eprintf("libcontacts_load_contacts:");
+ for (i = 0; contacts[i]; i++) {
+ if ((emails = contacts[i]->emails)) {
+ for (; (email = *emails); emails++) {
+ if (!email->address)
+ continue;
+ if (context && (!email->context || strcmp(email->context, context)))
+ continue;
+ if (list)
+ printf("%s (%s)\n", contacts[i]->id, email->address);
+ else if (!strcmp(email->address, argv[0]))
+ 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;
+}
diff --git a/find-contact-by-name.c b/find-contact-by-name.c
new file mode 100644
index 0000000..d99f0a8
--- /dev/null
+++ b/find-contact-by-name.c
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-F | -f | -l | -n] (-L | name)");
+
+
+int
+main(int argc, char *argv[])
+{
+ int list = 0;
+ struct passwd *user;
+ struct libcontacts_contact **contacts;
+ char *name;
+ size_t i, offset = 0;
+
+ ARGBEGIN {
+ case 'F':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, full_name);
+ break;
+ case 'f':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, first_name);
+ break;
+ case 'l':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, last_name);
+ break;
+ case 'n':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, nickname);
+ break;
+ case 'L':
+ list = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc != 1 - list)
+ usage();
+
+ if (!offset)
+ offset = offsetof(struct libcontacts_contact, name);
+
+ errno = 0;
+ user = getpwuid(getuid());
+ if (!user)
+ eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");
+
+ if (libcontacts_load_contacts(&contacts, user))
+ eprintf("libcontacts_load_contacts:");
+ for (i = 0; contacts[i]; i++) {
+ name = *(char **)&offset[(char *)contacts[i]];
+ if (list) {
+ if (name)
+ printf("%s (%s)\n", contacts[i]->id, name);
+ } else if (name && !strcmp(name, argv[0])) {
+ 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;
+}
diff --git a/find-contact-by-pgpkey.c b/find-contact-by-pgpkey.c
new file mode 100644
index 0000000..85d2202
--- /dev/null
+++ b/find-contact-by-pgpkey.c
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-c context] (-L | fingerprint)");
+
+
+int
+main(int argc, char *argv[])
+{
+ int list = 0;
+ struct passwd *user;
+ struct libcontacts_contact **contacts;
+ struct libcontacts_pgpkey **pgpkeys, *pgpkey;
+ char *context = NULL;
+ size_t i;
+
+ ARGBEGIN {
+ case 'c':
+ if (context)
+ usage();
+ context = ARG();
+ break;
+ 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))
+ eprintf("libcontacts_load_contacts:");
+ for (i = 0; contacts[i]; i++) {
+ if ((pgpkeys = contacts[i]->pgpkeys)) {
+ for (; (pgpkey = *pgpkeys); pgpkeys++) {
+ if (!pgpkey->id)
+ continue;
+ if (context && (!pgpkey->context || strcmp(pgpkey->context, context)))
+ continue;
+ if (list)
+ printf("%s (%s)\n", contacts[i]->id, pgpkey->id);
+ else if (!strcmp(pgpkey->id, argv[0]))
+ 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;
+}
diff --git a/find-contact-by-site.c b/find-contact-by-site.c
new file mode 100644
index 0000000..afda922
--- /dev/null
+++ b/find-contact-by-site.c
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-c context] (-L | address)");
+
+
+int
+main(int argc, char *argv[])
+{
+ int list = 0;
+ struct passwd *user;
+ struct libcontacts_contact **contacts;
+ struct libcontacts_site **sites, *site;
+ char *context = NULL;
+ size_t i;
+
+ ARGBEGIN {
+ case 'c':
+ if (context)
+ usage();
+ context = ARG();
+ break;
+ 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))
+ eprintf("libcontacts_load_contacts:");
+ for (i = 0; contacts[i]; i++) {
+ if ((sites = contacts[i]->sites)) {
+ for (; (site = *sites); sites++) {
+ if (!site->address)
+ continue;
+ if (context && (!site->context || strcmp(site->context, context)))
+ continue;
+ if (list)
+ printf("%s (%s)\n", contacts[i]->id, site->address);
+ else if (!strcmp(site->address, argv[0]))
+ 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;
+}
diff --git a/get-contact-emails.c b/get-contact-emails.c
new file mode 100644
index 0000000..433cf22
--- /dev/null
+++ b/get-contact-emails.c
@@ -0,0 +1,86 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-c context] [-a address] [-CA] contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ int display_ctx = 0, display_addr = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_email **emails, *email;
+ const char *lookup_ctx = NULL, *lookup_addr = NULL;
+ int ret = 0;
+ size_t i;
+
+ ARGBEGIN {
+ case 'c':
+ if (lookup_ctx)
+ usage();
+ lookup_ctx = ARG();
+ break;
+ case 'a':
+ if (lookup_addr)
+ usage();
+ lookup_addr = ARG();
+ break;
+ case 'C':
+ display_ctx = 1;
+ break;
+ case 'A':
+ display_addr = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ if (lookup_ctx && !lookup_addr && !display_ctx && !display_addr)
+ display_addr = 1;
+ if (lookup_addr && !lookup_ctx && !display_ctx && !display_addr)
+ display_ctx = 1;
+
+ 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;
+ } else {
+ for (emails = contact.emails; (email = *emails); emails++) {
+ if (lookup_ctx && (!email->context || strcmp(email->context, lookup_ctx)))
+ continue;
+ if (lookup_addr && (!email->address || strcmp(email->address, lookup_addr)))
+ continue;
+ if (lookup_ctx && lookup_addr && !display_ctx && !display_addr) {
+ printf("%s\n", *argv);
+ continue;
+ }
+ if (argc > 1)
+ printf("%s: ", *argv);
+ if (display_ctx && display_addr)
+ printf("%s: %s\n", email->context, email->address);
+ else if (display_addr)
+ printf("%s\n", email->address);
+ else
+ printf("%s\n", email->context);
+ }
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return ret;
+}
diff --git a/get-contact-file.c b/get-contact-file.c
new file mode 100644
index 0000000..e244941
--- /dev/null
+++ b/get-contact-file.c
@@ -0,0 +1,34 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+/* Useful for deleting or backing up contacts */
+
+USAGE("contact-id");
+
+
+int
+main(int argc, char *argv[])
+{
+ struct passwd *user;
+ char *path;
+
+ NOFLAGS(argc != 1);
+
+ if (!*argv[0] || strchr(argv[0], '/'))
+ usage();
+
+ errno = 0;
+ user = getpwuid(getuid());
+ if (!user)
+ eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");
+
+ path = libcontacts_get_path(argv[0], user);
+ if (!path)
+ eprintf("libcontacts_get_path %s:", argv[0]);
+
+ printf("%s\n", path);
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return 0;
+}
diff --git a/get-contact-gender.c b/get-contact-gender.c
new file mode 100644
index 0000000..32fef81
--- /dev/null
+++ b/get-contact-gender.c
@@ -0,0 +1,57 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-f] contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ int output_flag = 0, ret = 0;
+ size_t i;
+
+ ARGBEGIN {
+ case 'f':
+ output_flag = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ 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;
+ } else {
+ if (argc > 1)
+ printf("%s: ", *argv);
+ if (contact.gender == LIBCONTACTS_NOT_A_PERSON)
+ printf("%s\n", output_flag ? "-o" : "none");
+ else if (contact.gender == LIBCONTACTS_MALE)
+ printf("%s\n", output_flag ? "-m" : "male");
+ else if (contact.gender == LIBCONTACTS_FEMALE)
+ printf("%s\n", output_flag ? "-f" : "female");
+ else
+ printf("%s\n", output_flag ? "-u" : "unset");
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return ret;
+}
diff --git a/get-contact-name.c b/get-contact-name.c
new file mode 100644
index 0000000..8a0ae0c
--- /dev/null
+++ b/get-contact-name.c
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-F | -f | -l | n] contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ int ret = 0;
+ size_t i, offset = 0;
+ char *name;
+
+ ARGBEGIN {
+ case 'F':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, full_name);
+ break;
+ case 'f':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, first_name);
+ break;
+ case 'l':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, last_name);
+ break;
+ case 'n':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, nickname);
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ for (i = 0; argv[i]; i++)
+ if (!*argv[i] || strchr(argv[i], '/'))
+ usage();
+
+ if (!offset)
+ offset = offsetof(struct libcontacts_contact, name);
+
+ 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;
+ } else {
+ name = *(char **)&offset[(char *)&contact];
+ if (name) {
+ if (argc > 1)
+ printf("%s: ", *argv);
+ printf("%s\n", name);
+ }
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return ret;
+}
diff --git a/get-contact-notes.c b/get-contact-notes.c
new file mode 100644
index 0000000..96235b4
--- /dev/null
+++ b/get-contact-notes.c
@@ -0,0 +1,35 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("contact-id");
+
+
+int
+main(int argc, char *argv[])
+{
+ struct passwd *user;
+ struct libcontacts_contact contact;
+
+ NOFLAGS(argc != 1);
+
+ if (!*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");
+
+ if (contact.notes && *contact.notes) {
+ printf("%s", contact.notes);
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ }
+
+ libcontacts_contact_destroy(&contact);
+
+ return 0;
+}
diff --git a/get-contact-organisations.c b/get-contact-organisations.c
new file mode 100644
index 0000000..c16b333
--- /dev/null
+++ b/get-contact-organisations.c
@@ -0,0 +1,86 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-o organisation] [-t title] [-OT] contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ int display_org = 0, display_title = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_organisation **orgs, *org;
+ const char *lookup_org = NULL, *lookup_title = NULL;
+ int ret = 0;
+ size_t i;
+
+ ARGBEGIN {
+ case 'o':
+ if (lookup_org)
+ usage();
+ lookup_org = ARG();
+ break;
+ case 't':
+ if (lookup_title)
+ usage();
+ lookup_title = ARG();
+ break;
+ case 'O':
+ display_org = 1;
+ break;
+ case 'T':
+ display_title = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ if (lookup_org && !lookup_title && !display_org && !display_title)
+ display_title = 1;
+ if (lookup_title && !lookup_org && !display_org && !display_title)
+ display_org = 1;
+
+ 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;
+ } else {
+ for (orgs = contact.organisations; (org = *orgs); orgs++) {
+ if (lookup_org && (!org->organisation || strcmp(org->organisation, lookup_org)))
+ continue;
+ if (lookup_title && (!org->title || strcmp(org->title, lookup_title)))
+ continue;
+ if (lookup_org && lookup_title && !display_org && !display_title) {
+ printf("%s\n", *argv);
+ continue;
+ }
+ if (argc > 1)
+ printf("%s: ", *argv);
+ if (display_org && display_title)
+ printf("%s: %s\n", org->organisation, org->title);
+ else if (display_title)
+ printf("%s\n", org->title);
+ else
+ printf("%s\n", org->organisation);
+ }
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return ret;
+}
diff --git a/get-contact-pgpkeys.c b/get-contact-pgpkeys.c
new file mode 100644
index 0000000..9a1250a
--- /dev/null
+++ b/get-contact-pgpkeys.c
@@ -0,0 +1,86 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-c context] [-f fingerprint] [-CF] contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ int display_ctx = 0, display_id = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_pgpkey **keys, *key;
+ const char *lookup_ctx = NULL, *lookup_id = NULL;
+ int ret = 0;
+ size_t i;
+
+ ARGBEGIN {
+ case 'c':
+ if (lookup_ctx)
+ usage();
+ lookup_ctx = ARG();
+ break;
+ case 'f':
+ if (lookup_id)
+ usage();
+ lookup_id = ARG();
+ break;
+ case 'C':
+ display_ctx = 1;
+ break;
+ case 'F':
+ display_id = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ if (lookup_ctx && !lookup_id && !display_ctx && !display_id)
+ display_id = 1;
+ if (lookup_id && !lookup_ctx && !display_ctx && !display_id)
+ display_ctx = 1;
+
+ 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;
+ } else {
+ for (keys = contact.pgpkeys; (key = *keys); keys++) {
+ if (lookup_ctx && (!key->context || strcmp(key->context, lookup_ctx)))
+ continue;
+ if (lookup_id && (!key->id || strcmp(key->id, lookup_id)))
+ continue;
+ if (lookup_ctx && lookup_id && !display_ctx && !display_id) {
+ printf("%s\n", *argv);
+ continue;
+ }
+ if (argc > 1)
+ printf("%s: ", *argv);
+ if (display_ctx && display_id)
+ printf("%s: %s\n", key->context, key->id);
+ else if (display_id)
+ printf("%s\n", key->id);
+ else
+ printf("%s\n", key->context);
+ }
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return ret;
+}
diff --git a/get-contact-sites.c b/get-contact-sites.c
new file mode 100644
index 0000000..6627cc3
--- /dev/null
+++ b/get-contact-sites.c
@@ -0,0 +1,86 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-c context] [-a address] [-CA] contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ int display_ctx = 0, display_addr = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_site **sites, *site;
+ const char *lookup_ctx = NULL, *lookup_addr = NULL;
+ int ret = 0;
+ size_t i;
+
+ ARGBEGIN {
+ case 'c':
+ if (lookup_ctx)
+ usage();
+ lookup_ctx = ARG();
+ break;
+ case 'a':
+ if (lookup_addr)
+ usage();
+ lookup_addr = ARG();
+ break;
+ case 'C':
+ display_ctx = 1;
+ break;
+ case 'A':
+ display_addr = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ if (lookup_ctx && !lookup_addr && !display_ctx && !display_addr)
+ display_addr = 1;
+ if (lookup_addr && !lookup_ctx && !display_ctx && !display_addr)
+ display_ctx = 1;
+
+ 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;
+ } else {
+ for (sites = contact.sites; (site = *sites); sites++) {
+ if (lookup_ctx && (!site->context || strcmp(site->context, lookup_ctx)))
+ continue;
+ if (lookup_addr && (!site->address || strcmp(site->address, lookup_addr)))
+ continue;
+ if (lookup_ctx && lookup_addr && !display_ctx && !display_addr) {
+ printf("%s\n", *argv);
+ continue;
+ }
+ if (argc > 1)
+ printf("%s: ", *argv);
+ if (display_ctx && display_addr)
+ printf("%s: %s\n", site->context, site->address);
+ else if (display_addr)
+ printf("%s\n", site->address);
+ else
+ printf("%s\n", site->context);
+ }
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return ret;
+}
diff --git a/is-contact-ice.c b/is-contact-ice.c
new file mode 100644
index 0000000..057fc2d
--- /dev/null
+++ b/is-contact-ice.c
@@ -0,0 +1,41 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ int ret = 0;
+ size_t i;
+
+ NOFLAGS(!argc);
+
+ 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;
+ } else {
+ if (argc > 1)
+ printf("%s: ", *argv);
+ printf("%s\n", contact.in_case_of_emergency ? "yes" : "no");
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout))
+ eprintf("printf:");
+ return ret;
+}
diff --git a/list-contacts.c b/list-contacts.c
new file mode 100644
index 0000000..5983f24
--- /dev/null
+++ b/list-contacts.c
@@ -0,0 +1,84 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-efmnou]");
+
+
+int
+main(int argc, char *argv[])
+{
+ int names = 0, emergency = 0;
+ int include_men = 0, include_women = 0, include_orgs = 0, include_unspec = 0;
+ struct passwd *user;
+ struct libcontacts_contact **contacts;
+ char **ids;
+ size_t i;
+
+ ARGBEGIN {
+ case 'e':
+ emergency = 1;
+ break;
+ case 'f':
+ include_women = 1;
+ break;
+ case 'm':
+ include_men = 1;
+ break;
+ case 'n':
+ names = 1;
+ break;
+ case 'o':
+ include_orgs = 1;
+ break;
+ case 'u':
+ include_unspec = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc)
+ usage();
+
+ errno = 0;
+ user = getpwuid(getuid());
+ if (!user)
+ eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");
+
+ if (!names && !emergency && !include_men && !include_women && !include_orgs && !include_unspec) {
+ if (libcontacts_list_contacts(&ids, user))
+ eprintf("libcontacts_list_contacts:");
+ for (i = 0; ids[i]; i++) {
+ printf("%s\n", ids[i]);
+ free(ids[i]);
+ }
+ free(ids);
+ } else {
+ if (!include_men && !include_women && !include_orgs && !include_unspec)
+ include_men = include_women = include_orgs = include_unspec = 1;
+ if (libcontacts_load_contacts(&contacts, user))
+ eprintf("libcontacts_load_contacts:");
+ for (i = 0; contacts[i]; i++) {
+ if (emergency && !contacts[i]->in_case_of_emergency)
+ continue;
+ if (include_men && contacts[i]->gender == LIBCONTACTS_MALE);
+ else if (include_women && contacts[i]->gender == LIBCONTACTS_FEMALE);
+ else if (include_orgs && contacts[i]->gender == LIBCONTACTS_NOT_A_PERSON);
+ else if (include_unspec && contacts[i]->gender == LIBCONTACTS_UNSPECIFIED_GENDER);
+ else
+ continue;
+ if (names && contacts[i]->name)
+ printf("%s (%s)\n", contacts[i]->id, contacts[i]->name);
+ else
+ 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;
+}
diff --git a/set-contact-emails.c b/set-contact-emails.c
new file mode 100644
index 0000000..5911484
--- /dev/null
+++ b/set-contact-emails.c
@@ -0,0 +1,105 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-a | -c] contact-id context address | -u contact-id context [address] | -U contact-id [context] address");
+
+
+int
+main(int argc, char *argv[])
+{
+ int update_address = 0, update_context = 0;
+ int remove_by_context = 0, remove_by_address = 0;
+ int edit;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_email **r, **w;
+ size_t i;
+
+ ARGBEGIN {
+ case 'a':
+ update_address = 1;
+ break;
+ case 'c':
+ update_context = 1;
+ break;
+ case 'u':
+ remove_by_context = 1;
+ break;
+ case 'U':
+ remove_by_address = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ edit = update_address + update_context + remove_by_context + remove_by_address;
+ if (edit > 1 || argc < 3 - remove_by_context - remove_by_address || argc > 3)
+ usage();
+
+ if (!*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");
+
+ i = 0;
+ if (contact.emails) {
+ if (!edit) {
+ for (; contact.emails[i]; i++);
+ } else if (update_address) {
+ for (; contact.emails[i]; i++) {
+ if (contact.emails[i]->context && !strcmp(contact.emails[i]->context, argv[1])) {
+ free(contact.emails[i]->address);
+ contact.emails[i]->address = estrdup(argv[2]);
+ goto save;
+ }
+ }
+ } else if (update_context) {
+ for (; contact.emails[i]; i++) {
+ if (contact.emails[i]->address && !strcmp(contact.emails[i]->address, argv[2])) {
+ free(contact.emails[i]->context);
+ contact.emails[i]->context = estrdup(argv[1]);
+ goto save;
+ }
+ }
+ } else if (argc == 3) {
+ for (; contact.emails[i]; i++)
+ if (contact.emails[i]->context && !strcmp(contact.emails[i]->context, argv[1]))
+ if (contact.emails[i]->address && !strcmp(contact.emails[i]->address, argv[2]))
+ break;
+ } else if (remove_by_context) {
+ for (; contact.emails[i]; i++)
+ if (contact.emails[i]->context && !strcmp(contact.emails[i]->context, argv[1]))
+ break;
+ } else {
+ for (; contact.emails[i]; i++)
+ if (contact.emails[i]->address && !strcmp(contact.emails[i]->address, argv[1]))
+ break;
+ }
+ }
+ if (!edit || update_address || update_context) {
+ contact.emails = erealloc(contact.emails, (i + 2) * sizeof(*contact.emails));
+ contact.emails[i + 1] = NULL;
+ contact.emails[i] = ecalloc(1, sizeof(**contact.emails));
+ contact.emails[i]->context = estrdup(argv[1]);
+ contact.emails[i]->address = estrdup(argv[2]);
+ } else if (contact.emails && contact.emails[i]) {
+ libcontacts_email_destroy(contact.emails[i]);
+ free(contact.emails[i]);
+ for (r = &1[w = &contact.emails[i]]; *r;)
+ *w++ = *r++;
+ *w = NULL;
+ }
+
+save:
+ if (libcontacts_save_contact(&contact, user))
+ eprintf("libcontacts_save_contact %s:", argv[0]);
+ libcontacts_contact_destroy(&contact);
+
+ return 0;
+}
diff --git a/set-contact-gender.c b/set-contact-gender.c
new file mode 100644
index 0000000..f9750d6
--- /dev/null
+++ b/set-contact-gender.c
@@ -0,0 +1,71 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("(-f | -m | -o | -u) contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ enum libcontacts_gender gender = LIBCONTACTS_UNSPECIFIED_GENDER;
+ int gender_specified = 0, ret = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ size_t i;
+
+ ARGBEGIN {
+ case 'f':
+ if (gender_specified)
+ usage();
+ gender_specified = 1;
+ gender = LIBCONTACTS_FEMALE;
+ break;
+ case 'm':
+ if (gender_specified)
+ usage();
+ gender_specified = 1;
+ gender = LIBCONTACTS_MALE;
+ break;
+ case 'o':
+ if (gender_specified)
+ usage();
+ gender_specified = 1;
+ gender = LIBCONTACTS_NOT_A_PERSON;
+ break;
+ case 'u':
+ if (gender_specified)
+ usage();
+ gender_specified = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!gender_specified || !argc)
+ usage();
+
+ 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;
+ } else {
+ contact.gender = gender;
+ if (libcontacts_save_contact(&contact, user)) {
+ weprintf("libcontacts_save_contact %s:", *argv);
+ ret = 1;
+ }
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ return ret;
+}
diff --git a/set-contact-ice.c b/set-contact-ice.c
new file mode 100644
index 0000000..2dcb612
--- /dev/null
+++ b/set-contact-ice.c
@@ -0,0 +1,50 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-u] contact-id ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ int set_ice = 1, ret = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ size_t i;
+
+ ARGBEGIN {
+ case 'u':
+ set_ice = 0;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ 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;
+ } else {
+ contact.in_case_of_emergency = set_ice;
+ if (libcontacts_save_contact(&contact, user)) {
+ weprintf("libcontacts_save_contact %s:", *argv);
+ ret = 1;
+ }
+ libcontacts_contact_destroy(&contact);
+ }
+ }
+
+ return ret;
+}
diff --git a/set-contact-name.c b/set-contact-name.c
new file mode 100644
index 0000000..dad34d1
--- /dev/null
+++ b/set-contact-name.c
@@ -0,0 +1,72 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-F | -f | -l | n] (-u contact-id | contact-id name)");
+
+
+int
+main(int argc, char *argv[])
+{
+ int unset = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ size_t offset = 0;
+ char **namep;
+
+ ARGBEGIN {
+ case 'F':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, full_name);
+ break;
+ case 'f':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, first_name);
+ break;
+ case 'l':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, last_name);
+ break;
+ case 'n':
+ if (offset)
+ usage();
+ offset = offsetof(struct libcontacts_contact, nickname);
+ break;
+ case 'u':
+ unset = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc != 2 - unset)
+ usage();
+
+ if (!*argv[0] || strchr(argv[0], '/'))
+ usage();
+
+ if (!offset)
+ offset = offsetof(struct libcontacts_contact, name);
+
+ errno = 0;
+ user = getpwuid(getuid());
+ if (!user)
+ eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");
+
+ if (libcontacts_load_contact(*argv, &contact, user))
+ eprintf("libcontacts_load_contact %s: %s\n", *argv, errno ? strerror(errno) : "contact file is malformatted");
+
+ namep = (char **)&offset[(char *)&contact];
+ if (!unset || *namep) {
+ free(*namep);
+ *namep = unset ? NULL : estrdup(argv[1]);
+
+ if (libcontacts_save_contact(&contact, user))
+ eprintf("libcontacts_save_contact %s:", *argv);
+ }
+
+ libcontacts_contact_destroy(&contact);
+ return 0;
+}
diff --git a/set-contact-notes.c b/set-contact-notes.c
new file mode 100644
index 0000000..6eeeeb4
--- /dev/null
+++ b/set-contact-notes.c
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-u] contact-id");
+
+
+int
+main(int argc, char *argv[])
+{
+ int unset = 0;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ size_t size = 0, len = 0;
+ ssize_t r;
+
+ ARGBEGIN {
+ case 'u':
+ unset = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc != 1)
+ usage();
+
+ if (!*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");
+
+ free(contact.notes);
+ contact.notes = NULL;
+ if (!unset) {
+ for (;;) {
+ if (len == size)
+ contact.notes = erealloc(contact.notes, size += 512);
+ r = read(STDIN_FILENO, &contact.notes[len], size - len);
+ if (r <= 0) {
+ if (!r)
+ break;
+ eprintf("read <stdin>:");
+ }
+ len += (size_t)r;
+ }
+ if (size)
+ contact.notes[len] = '\0';
+ }
+
+ if (libcontacts_save_contact(&contact, user))
+ eprintf("libcontacts_save_contact %s:", argv[0]);
+
+ libcontacts_contact_destroy(&contact);
+
+ return 0;
+}
diff --git a/set-contact-organisations.c b/set-contact-organisations.c
new file mode 100644
index 0000000..17db004
--- /dev/null
+++ b/set-contact-organisations.c
@@ -0,0 +1,106 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-o | -t] contact-id organisation title | -u contact-id organisation [title] | -U contact-id [organisation] title");
+
+
+int
+main(int argc, char *argv[])
+{
+ int update_title = 0, update_organisation = 0;
+ int remove_by_organisation = 0, remove_by_title = 0;
+ int edit;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_organisation **r, **w;
+ size_t i;
+
+ ARGBEGIN {
+ case 'o':
+ update_title = 1;
+ break;
+ case 't':
+ update_organisation = 1;
+ break;
+ case 'u':
+ remove_by_organisation = 1;
+ break;
+ case 'U':
+ remove_by_title = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ edit = update_title + update_organisation + remove_by_organisation + remove_by_title;
+ if (edit > 1 || argc < 3 - remove_by_organisation - remove_by_title || argc > 3)
+ usage();
+
+ if (!*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");
+
+ i = 0;
+ if (contact.organisations) {
+ if (!edit) {
+ for (; contact.organisations[i]; i++);
+ } else if (update_title) {
+ for (; contact.organisations[i]; i++) {
+ if (contact.organisations[i]->organisation &&
+ !strcmp(contact.organisations[i]->organisation, argv[1])) {
+ free(contact.organisations[i]->title);
+ contact.organisations[i]->title = estrdup(argv[2]);
+ goto save;
+ }
+ }
+ } else if (update_organisation) {
+ for (; contact.organisations[i]; i++) {
+ if (contact.organisations[i]->title && !strcmp(contact.organisations[i]->title, argv[2])) {
+ free(contact.organisations[i]->organisation);
+ contact.organisations[i]->organisation = estrdup(argv[1]);
+ goto save;
+ }
+ }
+ } else if (argc == 3) {
+ for (; contact.organisations[i]; i++)
+ if (contact.organisations[i]->organisation && !strcmp(contact.organisations[i]->organisation, argv[1]))
+ if (contact.organisations[i]->title && !strcmp(contact.organisations[i]->title, argv[2]))
+ break;
+ } else if (remove_by_organisation) {
+ for (; contact.organisations[i]; i++)
+ if (contact.organisations[i]->organisation && !strcmp(contact.organisations[i]->organisation, argv[1]))
+ break;
+ } else {
+ for (; contact.organisations[i]; i++)
+ if (contact.organisations[i]->title && !strcmp(contact.organisations[i]->title, argv[1]))
+ break;
+ }
+ }
+ if (!edit || update_title || update_organisation) {
+ contact.organisations = erealloc(contact.organisations, (i + 2) * sizeof(*contact.organisations));
+ contact.organisations[i + 1] = NULL;
+ contact.organisations[i] = ecalloc(1, sizeof(**contact.organisations));
+ contact.organisations[i]->organisation = estrdup(argv[1]);
+ contact.organisations[i]->title = estrdup(argv[2]);
+ } else if (contact.organisations && contact.organisations[i]) {
+ libcontacts_organisation_destroy(contact.organisations[i]);
+ free(contact.organisations[i]);
+ for (r = &1[w = &contact.organisations[i]]; *r;)
+ *w++ = *r++;
+ *w = NULL;
+ }
+
+save:
+ if (libcontacts_save_contact(&contact, user))
+ eprintf("libcontacts_save_contact %s:", argv[0]);
+ libcontacts_contact_destroy(&contact);
+
+ return 0;
+}
diff --git a/set-contact-pgpkeys.c b/set-contact-pgpkeys.c
new file mode 100644
index 0000000..b5bebfb
--- /dev/null
+++ b/set-contact-pgpkeys.c
@@ -0,0 +1,105 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-c | -f] contact-id context fingerprint | -u contact-id context [fingerprint] | -U contact-id [context] fingerprint");
+
+
+int
+main(int argc, char *argv[])
+{
+ int update_id = 0, update_context = 0;
+ int remove_by_context = 0, remove_by_id = 0;
+ int edit;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_pgpkey **r, **w;
+ size_t i;
+
+ ARGBEGIN {
+ case 'c':
+ update_context = 1;
+ break;
+ case 'f':
+ update_id = 1;
+ break;
+ case 'u':
+ remove_by_context = 1;
+ break;
+ case 'U':
+ remove_by_id = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ edit = update_id + update_context + remove_by_context + remove_by_id;
+ if (edit > 1 || argc < 3 - remove_by_context - remove_by_id || argc > 3)
+ usage();
+
+ if (!*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");
+
+ i = 0;
+ if (contact.pgpkeys) {
+ if (!edit) {
+ for (; contact.pgpkeys[i]; i++);
+ } else if (update_id) {
+ for (; contact.pgpkeys[i]; i++) {
+ if (contact.pgpkeys[i]->context && !strcmp(contact.pgpkeys[i]->context, argv[1])) {
+ free(contact.pgpkeys[i]->id);
+ contact.pgpkeys[i]->id = estrdup(argv[2]);
+ goto save;
+ }
+ }
+ } else if (update_context) {
+ for (; contact.pgpkeys[i]; i++) {
+ if (contact.pgpkeys[i]->id && !strcmp(contact.pgpkeys[i]->id, argv[2])) {
+ free(contact.pgpkeys[i]->context);
+ contact.pgpkeys[i]->context = estrdup(argv[1]);
+ goto save;
+ }
+ }
+ } else if (argc == 3) {
+ for (; contact.pgpkeys[i]; i++)
+ if (contact.pgpkeys[i]->context && !strcmp(contact.pgpkeys[i]->context, argv[1]))
+ if (contact.pgpkeys[i]->id && !strcmp(contact.pgpkeys[i]->id, argv[2]))
+ break;
+ } else if (remove_by_context) {
+ for (; contact.pgpkeys[i]; i++)
+ if (contact.pgpkeys[i]->context && !strcmp(contact.pgpkeys[i]->context, argv[1]))
+ break;
+ } else {
+ for (; contact.pgpkeys[i]; i++)
+ if (contact.pgpkeys[i]->id && !strcmp(contact.pgpkeys[i]->id, argv[1]))
+ break;
+ }
+ }
+ if (!edit || update_id || update_context) {
+ contact.pgpkeys = erealloc(contact.pgpkeys, (i + 2) * sizeof(*contact.pgpkeys));
+ contact.pgpkeys[i + 1] = NULL;
+ contact.pgpkeys[i] = ecalloc(1, sizeof(**contact.pgpkeys));
+ contact.pgpkeys[i]->context = estrdup(argv[1]);
+ contact.pgpkeys[i]->id = estrdup(argv[2]);
+ } else if (contact.pgpkeys && contact.pgpkeys[i]) {
+ libcontacts_pgpkey_destroy(contact.pgpkeys[i]);
+ free(contact.pgpkeys[i]);
+ for (r = &1[w = &contact.pgpkeys[i]]; *r;)
+ *w++ = *r++;
+ *w = NULL;
+ }
+
+save:
+ if (libcontacts_save_contact(&contact, user))
+ eprintf("libcontacts_save_contact %s:", argv[0]);
+ libcontacts_contact_destroy(&contact);
+
+ return 0;
+}
diff --git a/set-contact-sites.c b/set-contact-sites.c
new file mode 100644
index 0000000..e826f73
--- /dev/null
+++ b/set-contact-sites.c
@@ -0,0 +1,105 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-a | -c] contact-id context address | -u contact-id context [address] | -U contact-id [context] address");
+
+
+int
+main(int argc, char *argv[])
+{
+ int update_address = 0, update_context = 0;
+ int remove_by_context = 0, remove_by_address = 0;
+ int edit;
+ struct passwd *user;
+ struct libcontacts_contact contact;
+ struct libcontacts_site **r, **w;
+ size_t i;
+
+ ARGBEGIN {
+ case 'a':
+ update_address = 1;
+ break;
+ case 'c':
+ update_context = 1;
+ break;
+ case 'u':
+ remove_by_context = 1;
+ break;
+ case 'U':
+ remove_by_address = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ edit = update_address + update_context + remove_by_context + remove_by_address;
+ if (edit > 1 || argc < 3 - remove_by_context - remove_by_address || argc > 3)
+ usage();
+
+ if (!*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");
+
+ i = 0;
+ if (contact.sites) {
+ if (!edit) {
+ for (; contact.sites[i]; i++);
+ } else if (update_address) {
+ for (; contact.sites[i]; i++) {
+ if (contact.sites[i]->context && !strcmp(contact.sites[i]->context, argv[1])) {
+ free(contact.sites[i]->address);
+ contact.sites[i]->address = estrdup(argv[2]);
+ goto save;
+ }
+ }
+ } else if (update_context) {
+ for (; contact.sites[i]; i++) {
+ if (contact.sites[i]->address && !strcmp(contact.sites[i]->address, argv[2])) {
+ free(contact.sites[i]->context);
+ contact.sites[i]->context = estrdup(argv[1]);
+ goto save;
+ }
+ }
+ } else if (argc == 3) {
+ for (; contact.sites[i]; i++)
+ if (contact.sites[i]->context && !strcmp(contact.sites[i]->context, argv[1]))
+ if (contact.sites[i]->address && !strcmp(contact.sites[i]->address, argv[2]))
+ break;
+ } else if (remove_by_context) {
+ for (; contact.sites[i]; i++)
+ if (contact.sites[i]->context && !strcmp(contact.sites[i]->context, argv[1]))
+ break;
+ } else {
+ for (; contact.sites[i]; i++)
+ if (contact.sites[i]->address && !strcmp(contact.sites[i]->address, argv[1]))
+ break;
+ }
+ }
+ if (!edit || update_address || update_context) {
+ contact.sites = erealloc(contact.sites, (i + 2) * sizeof(*contact.sites));
+ contact.sites[i + 1] = NULL;
+ contact.sites[i] = ecalloc(1, sizeof(**contact.sites));
+ contact.sites[i]->context = estrdup(argv[1]);
+ contact.sites[i]->address = estrdup(argv[2]);
+ } else if (contact.sites && contact.sites[i]) {
+ libcontacts_site_destroy(contact.sites[i]);
+ free(contact.sites[i]);
+ for (r = &1[w = &contact.sites[i]]; *r;)
+ *w++ = *r++;
+ *w = NULL;
+ }
+
+save:
+ if (libcontacts_save_contact(&contact, user))
+ eprintf("libcontacts_save_contact %s:", argv[0]);
+ libcontacts_contact_destroy(&contact);
+
+ return 0;
+}