aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Makefile5
-rw-r--r--TODO4
-rw-r--r--libcontacts.h4
-rw-r--r--libcontacts_address_destroy.334
-rw-r--r--libcontacts_birthday_destroy.334
-rw-r--r--libcontacts_block_destroy.334
-rw-r--r--libcontacts_chat_destroy.334
-rw-r--r--libcontacts_contact_destroy.344
-rw-r--r--libcontacts_email_destroy.334
-rw-r--r--libcontacts_format_contact.352
-rw-r--r--libcontacts_get_path.394
-rw-r--r--libcontacts_list_contacts.367
-rw-r--r--libcontacts_load_contact.375
-rw-r--r--libcontacts_load_contact.c12
-rw-r--r--libcontacts_load_contacts.374
-rw-r--r--libcontacts_number_destroy.334
-rw-r--r--libcontacts_organisation_destroy.334
-rw-r--r--libcontacts_parse_contact.380
-rw-r--r--libcontacts_parse_contact.c235
-rw-r--r--libcontacts_pgpkey_destroy.334
-rw-r--r--libcontacts_same_number.374
-rw-r--r--libcontacts_save_contact.378
-rw-r--r--libcontacts_save_contact.c8
-rw-r--r--libcontacts_site_destroy.334
-rw-r--r--test.c1
25 files changed, 1087 insertions, 126 deletions
diff --git a/Makefile b/Makefile
index 4a543c8..01c9712 100644
--- a/Makefile
+++ b/Makefile
@@ -42,6 +42,8 @@ HDR =\
LOBJ = $(OBJ:.o=.lo)
+MAN3 = $(OBJ:.o=.3)
+
all: libcontacts.a libcontacts.$(LIBEXT) test
$(OBJ): $($@:.o=.c) $(HDR)
@@ -72,11 +74,13 @@ check: test
install: libcontacts.a libcontacts.$(LIBEXT)
mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
mkdir -p -- "$(DESTDIR)$(PREFIX)/include"
+ mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man3"
cp -- libcontacts.a "$(DESTDIR)$(PREFIX)/lib/"
cp -- libcontacts.h "$(DESTDIR)$(PREFIX)/include/"
cp -- libcontacts.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/libcontacts.$(LIBMINOREXT)"
ln -sf -- libcontacts.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libcontacts.$(LIBMAJOREXT)"
ln -sf -- libcontacts.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libcontacts.$(LIBEXT)"
+ cp -- $(MAN3) "$(DESTDIR)$(MANPREFIX)/man3/"
uninstall:
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libcontacts.$(LIBMAJOREXT)"
@@ -84,6 +88,7 @@ uninstall:
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libcontacts.$(LIBEXT)"
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libcontacts.a"
-rm -f -- "$(DESTDIR)$(PREFIX)/include/libcontacts.h"
+ -cd -- "$(DESTDIR)$(MANPREFIX)/man3/" && rm -rf -- $(MAN3)
clean:
-rm -rf -- *.o *.a *.lo *.so *.dylib *.dll *.su test .testdir
diff --git a/TODO b/TODO
index 6c085d3..8f00e88 100644
--- a/TODO
+++ b/TODO
@@ -1 +1,3 @@
-Add man pages
+Add libcontacts.7
+Add libcontacts.h.0
+Add contacts.5
diff --git a/libcontacts.h b/libcontacts.h
index 98bce5b..6ce77d2 100644
--- a/libcontacts.h
+++ b/libcontacts.h
@@ -292,13 +292,13 @@ struct libcontacts_contact {
void libcontacts_contact_destroy(struct libcontacts_contact *);
int libcontacts_list_contacts(char ***, const struct passwd *, int);
-int libcontacts_load_contact(const char *, struct libcontacts_contact *, const struct passwd *); /* errno = 0 if malformatted */
+int libcontacts_load_contact(const char *, struct libcontacts_contact *, const struct passwd *);
int libcontacts_load_contacts(struct libcontacts_contact ***, const struct passwd *, int);
int libcontacts_save_contact(struct libcontacts_contact *, const struct passwd *);
int libcontacts_same_number(const char *, const char *, const char *, const char *); /* might be removed in the future */
char *libcontacts_get_path(const char *, const struct passwd *);
-int libcontacts_parse_contact(char *, struct libcontacts_contact *); /* does not load .id, not stored in file, but is the filename */
+int libcontacts_parse_contact(char *, struct libcontacts_contact *);
int libcontacts_format_contact(const struct libcontacts_contact *, char **);
void libcontacts_block_destroy(struct libcontacts_block *);
diff --git a/libcontacts_address_destroy.3 b/libcontacts_address_destroy.3
new file mode 100644
index 0000000..cc5c606
--- /dev/null
+++ b/libcontacts_address_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_ADDRESS_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_address_destroy \- Deallocate memory for a contact address entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_address_destroy(struct libcontacts_address *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_address_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_birthday_destroy.3 b/libcontacts_birthday_destroy.3
new file mode 100644
index 0000000..d9ba628
--- /dev/null
+++ b/libcontacts_birthday_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_BIRTHDAY_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_birthday_destroy \- Deallocate memory for a contact birthday entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_birthday_destroy(struct libcontacts_birthday *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_birthday_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_block_destroy.3 b/libcontacts_block_destroy.3
new file mode 100644
index 0000000..3742b52
--- /dev/null
+++ b/libcontacts_block_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_BLOCK_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_block_destroy \- Deallocate memory for a contact block entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_block_destroy(struct libcontacts_block *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_block_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_chat_destroy.3 b/libcontacts_chat_destroy.3
new file mode 100644
index 0000000..e504b64
--- /dev/null
+++ b/libcontacts_chat_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_CHAT_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_chat_destroy \- Deallocate memory for a contact chat service address entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_chat_destroy(struct libcontacts_chat *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_chat_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_contact_destroy.3 b/libcontacts_contact_destroy.3
new file mode 100644
index 0000000..910c245
--- /dev/null
+++ b/libcontacts_contact_destroy.3
@@ -0,0 +1,44 @@
+.TH LIBCONTACTS_CONTACT_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_contact_destroy \- Deallocate memory for a contact entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_contact_destroy(struct libcontacts_contact *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_contact_destroy ()
+function deallocates the memory stored in
+.IR *entry ,
+including any subentries that are deallocatable
+with other functions provided by libcontacts.
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_address_destroy (3),
+.BR libcontacts_birthday_destroy (3),
+.BR libcontacts_block_destroy (3),
+.BR libcontacts_chat_destroy (3),
+.BR libcontacts_email_destroy (3),
+.BR libcontacts_number_destroy (3),
+.BR libcontacts_organisation_destroy (3),
+.BR libcontacts_pgpkey_destroy (3),
+.BR libcontacts_site_destroy (3)
diff --git a/libcontacts_email_destroy.3 b/libcontacts_email_destroy.3
new file mode 100644
index 0000000..387bd18
--- /dev/null
+++ b/libcontacts_email_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_EMAIL_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_email_destroy \- Deallocate memory for a contact e-mail address entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_email_destroy(struct libcontacts_email *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_email_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_format_contact.3 b/libcontacts_format_contact.3
new file mode 100644
index 0000000..59de67c
--- /dev/null
+++ b/libcontacts_format_contact.3
@@ -0,0 +1,52 @@
+.TH LIBCONTACTS_FORMAT_CONTACT 3 LIBCONTACTS
+.SH NAME
+libcontacts_format_contact \- Construct a contact file
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_format_contact(const struct libcontacts_contact *\fIcontact\fP, char **\fIdatap\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_format_contact ()
+function formats the content that shall be stored
+the a contact file, for the contact in the
+.I contact
+parameter. The resulting content will be NUL-terminated
+and, upon successful completion, stored in
+.IR *datap .
+The caller must manually deallocate the content with the
+.BR free (3)
+function when it's no longer needed.
+
+.SH RETURN VALUE
+The
+.BR libcontacts_format_contact ()
+function returns 0 upon successful completion;
+otherwise -1 is returned and
+.I errno
+is set appropriately to indicate the error.
+
+.SH ERRORS
+The
+.BR libcontacts_format_contact ()
+function may fail for any reason specified for the
+.BR open_memstream (3)
+and
+.BR fprintf (3)
+(other than
+.IR EILSEQ )
+functions.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7)
+.BR libcontacts_save_contact (3),
+.BR libcontacts_parse_contact (3),
+.BR libcontacts_get_file (3),
+.BR contacts (5),
diff --git a/libcontacts_get_path.3 b/libcontacts_get_path.3
new file mode 100644
index 0000000..d1e62f2
--- /dev/null
+++ b/libcontacts_get_path.3
@@ -0,0 +1,94 @@
+.TH LIBCONTACTS_GET_PATH 3 LIBCONTACTS
+.SH NAME
+libcontacts_get_path \- Get the file information for a contact is or would be stored in
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+char *libcontacts_get_path(const char *\fIid\fP, const struct passwd *\fIuser\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_get_path ()
+function get the path to the file for the contact with
+the ID specified in the
+.I id
+parameter, neither this file nor its directory need exist
+for successful completion to the place. If
+.I id
+is the empty string, the directory where all contacts is
+returned with a trailing slash
+.RB ( / ).
+.PP
+.I user
+shall be the user's entry in the password database (not
+the shadow database). This is used for the get user's
+home directory.
+
+.SH RETURN VALUE
+The
+.BR libcontacts_get_path ()
+function returns the path the file where the information
+for the specified contact is stored (or if requested,
+the directory where contact files are stored) upon successful
+completion; on failure
+.I NULL
+is returned and
+.I errno
+is set appropriately to indicate the error.
+
+.SH ERRORS
+The
+.BR libcontacts_get_path ()
+function will fail if:
+.TP
+.B EINVAL
+Either parameter is
+.I NULL
+or the home directory field in
+.I user
+is
+.I NULL
+or the empty string.
+.PP
+The
+.BR libcontacts_get_path ()
+function may also fail for any reason specified for the
+.BR malloc (3)
+function.
+
+.SH EXTENDED DESCRIPTION
+All contact file shall be stored in
+.I .config/contacts/
+within the user's home directory. All environment variables
+shall be ignored.
+.PP
+The contact ID
+.RI ( id )
+must not contain slashes, and should ideally only contain
+lower case ASCII letters, ASCII digits, and ASCII hyphens.
+Contact ID's starting with a dot have special meaning,
+currently define ones are:
+.TP
+.B .me
+Contact information for the user.
+.TP
+.B .groups
+Pseudo-contact where groups that how no members can be
+stored.
+.PP
+The contact ID
+.RI ( id )
+must end with a tilde, these are used to write to until
+file system synchronisation has takes place for the file,
+and the file is subsequently renamed.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_load_contact (7),
+.BR libcontacts_save_contact (7)
diff --git a/libcontacts_list_contacts.3 b/libcontacts_list_contacts.3
new file mode 100644
index 0000000..abe4365
--- /dev/null
+++ b/libcontacts_list_contacts.3
@@ -0,0 +1,67 @@
+.TH LIBCONTACTS_LIST_CONTACTS 3 LIBCONTACTS
+.SH NAME
+libcontacts_list_contacts \- Get a list of all contacts
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_list_contacts(char ***\fIidsp\fP, const struct passwd *\fIuser\fP, int \fIwith_me\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_list_contacts ()
+function create a
+.IR NULL -termianted
+list of all regular contact entries and stores it in
+.I *idsp
+upon successful completion. If
+.I with_me
+is non-zero, the
+.B .me
+entry will also be included, if it exists.
+.PP
+.I user
+shall be the user's entry in the password database (not
+the shadow database). This is used for the get user's
+home directory.
+.PP
+When no longer needed, the caller shall manually
+deallocate all elements in
+.I *idsp
+along with
+.I *idsp
+itself, using the
+.BR free (3)
+function.
+
+.SH RETURN VALUE
+The
+.BR libcontacts_list_contacts ()
+function returns 0 upon successful completion;
+otherwise -1 is returned and
+.I errno
+is set appropriately to indicate the error.
+
+.SH ERRORS
+The
+.BR libcontacts_list_contacts ()
+function may fail for any reason specified for the
+.BR libcontacts_get_path (3),
+.BR opendir (3)
+(other than
+.IR ENOENT ),
+.BR realloc (3),
+and
+.BR readdir (3)
+functions.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_get_path (3),
+.BR libcontacts_load_contact (3),
+.BR libcontacts_load_contacts (3)
diff --git a/libcontacts_load_contact.3 b/libcontacts_load_contact.3
new file mode 100644
index 0000000..e6f5521
--- /dev/null
+++ b/libcontacts_load_contact.3
@@ -0,0 +1,75 @@
+.TH LIBCONTACTS_LOAD_CONTACT 3 LIBCONTACTS
+.SH NAME
+libcontacts_load_contact \- Load a contact
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_load_contact(const char *\fIid\fP, struct libcontacts_contact *\fIcontactp\fP, const struct passwd *\fIuser\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_load_contact ()
+function loads the entry of the contact, whose ID
+is specified in the
+.I id
+parameter, and store it in
+.I *contactp
+upon successful completion.
+.PP
+.I user
+shall be the user's entry in the password database (not
+the shadow database). This is used for the get user's
+home directory.
+.PP
+When no longer needed, the caller shall manually
+deallocate all member stored in
+.I *contactp
+using the
+.BR libcontacts_contact_destroy (3)
+function.
+.PP
+The pointer
+.I id
+will be copied to
+.IR contactp->id .
+
+.SH RETURN VALUE
+The
+.BR libcontacts_load_contact ()
+function returns 0 upon successful completion;
+otherwise -1 is returned and
+.I errno
+is set appropriately to indicate the error.
+
+.SH ERRORS
+The
+.BR libcontacts_load_contact ()
+function will fail if:
+.TP
+.B 0
+The file it loads contains a NUL byte.
+.PP
+The
+.BR libcontacts_load_contact ()
+function may fail for any reason specified for the
+.BR libcontacts_get_path (3),
+.BR libcontacts_parse_contact (3),
+.BR open (3),
+.BR realloc (3),
+and
+.BR read (3)
+functions.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_loads_contact (3),
+.BR libcontacts_save_contact (3),
+.BR libcontacts_contact_destroy (3),
+.BR libcontacts_list_contacts (3),
+.BR libcontacts_parse_contact (3)
diff --git a/libcontacts_load_contact.c b/libcontacts_load_contact.c
index 0821871..af931f9 100644
--- a/libcontacts_load_contact.c
+++ b/libcontacts_load_contact.c
@@ -3,7 +3,7 @@
int
-libcontacts_load_contact(const char *id, struct libcontacts_contact *contact, const struct passwd *user)
+libcontacts_load_contact(const char *id, struct libcontacts_contact *contactp, const struct passwd *user)
{
int ret, fd, saved_errno;
char *data = NULL, *path;
@@ -11,7 +11,7 @@ libcontacts_load_contact(const char *id, struct libcontacts_contact *contact, co
ssize_t r;
void *new;
- if (!contact) {
+ if (!contactp) {
errno = EINVAL;
return -1;
}
@@ -48,11 +48,11 @@ libcontacts_load_contact(const char *id, struct libcontacts_contact *contact, co
}
close(fd);
- ret = libcontacts_parse_contact(data, contact);
+ ret = libcontacts_parse_contact(data, contactp);
free(data);
- if (!ret && !(contact->id = strdup(id))) {
- libcontacts_contact_destroy(contact);
- memset(contact, 0, sizeof(*contact));
+ if (!ret && !(contactp->id = strdup(id))) {
+ libcontacts_contact_destroy(contactp);
+ memset(contactp, 0, sizeof(*contactp));
return -1;
}
return ret;
diff --git a/libcontacts_load_contacts.3 b/libcontacts_load_contacts.3
new file mode 100644
index 0000000..6b0649b
--- /dev/null
+++ b/libcontacts_load_contacts.3
@@ -0,0 +1,74 @@
+.TH LIBCONTACTS_LOAD_CONTACTS 3 LIBCONTACTS
+.SH NAME
+libcontacts_load_contacts \- Load all contacts
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_load_contacts(struct libcontacts_contact ***\fIcontactsp\fP, const struct passwd *\fIuser\fP, int \fIwith_me\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_load_contacts ()
+function loads all regular contact entries and stores
+them as a
+.IR NULL -termianted
+list in
+.I *contactsp
+upon successful completion. If
+.I with_me
+is non-zero, the
+.B .me
+entry will also be included, if it exists.
+.PP
+.I user
+shall be the user's entry in the password database (not
+the shadow database). This is used for the get user's
+home directory.
+.PP
+When no longer needed, the caller shall manually
+deallocate all elements in
+.IR *contactsp ,
+using the
+.BR libcontacts_contact_destroy (3)
+and
+.BR free (3)
+functions, along with
+.I *contactsp
+itself, using the
+.BR free (3)
+function.
+
+.SH RETURN VALUE
+The
+.BR libcontacts_load_contacts ()
+function returns 0 upon successful completion;
+otherwise -1 is returned and
+.I errno
+is set appropriately to indicate the error.
+
+.SH ERRORS
+The
+.BR libcontacts_load_contacts ()
+function may fail for any reason specified for the
+.BR libcontacts_list_contacts (3),
+.BR libcontacts_load_contacts (3)
+(other than
+.I ENOENT
+and
+.IR EACCES ),
+and
+.BR calloc (3)
+functions.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_load_contact (3),
+.BR libcontacts_save_contact (3),
+.BR libcontacts_contact_destroy (3),
+.BR libcontacts_list_contacts (3)
diff --git a/libcontacts_number_destroy.3 b/libcontacts_number_destroy.3
new file mode 100644
index 0000000..5f3cafc
--- /dev/null
+++ b/libcontacts_number_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_NUMBER_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_number_destroy \- Deallocate memory for a contact telephone number entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_number_destroy(struct libcontacts_number *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_number_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_organisation_destroy.3 b/libcontacts_organisation_destroy.3
new file mode 100644
index 0000000..f192eb1
--- /dev/null
+++ b/libcontacts_organisation_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_ORGANISATION_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_organisation_destroy \- Deallocate memory for a contact organisation membership entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_organisation_destroy(struct libcontacts_organisation *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_organisation_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_parse_contact.3 b/libcontacts_parse_contact.3
new file mode 100644
index 0000000..f2474d6
--- /dev/null
+++ b/libcontacts_parse_contact.3
@@ -0,0 +1,80 @@
+.TH LIBCONTACTS_PARSE_CONTACT 3 LIBCONTACTS
+.SH NAME
+libcontacts_parse_contact \- Parse a contact file
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_parse_contact(char *\fIdata\fP, struct libcontacts_contact *\fIcontact\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_parse_contact ()
+function parses the content of a contact file.
+The file content shall be NUL-terminated and
+given in the
+.I data
+parameter. The resulting contact information
+will be stored in the
+.IR *contact .
+The user is responsable for deallocating the
+result when it's no longer needed, using the
+.BR libcontacts_contact_destroy (3)
+function, or manually with
+.BR free (3),
+and the various functions references in the
+.B SEE ALSO
+section.
+.PP
+Note that the file contents do not contain the
+contact ID, so
+.I contact->id
+will be set to
+.IR NULL .
+.PP
+Also note that the contents of
+.I data
+may be modified by the function during the
+execution of the function, it will however be
+restored before the function returns.
+
+.SH RETURN VALUE
+The
+.BR libcontacts_parse_contact ()
+function returns 0 upon successful completion;
+otherwise -1 is returned and
+.I errno
+is set appropriately to indicate the error.
+
+.SH ERRORS
+The
+.BR libcontacts_parse_contact ()
+function may fail for any reason specified for the
+.BR open_memstream (3)
+and
+.BR fprintf (3)
+(other than
+.IR EILSEQ )
+functions.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7)
+.BR libcontacts_load_contact (3),
+.BR libcontacts_format_contact (3),
+.BR libcontacts_get_file (3),
+.BR libcontacts_contact_destroy (3),
+.BR libcontacts_address_destroy (3),
+.BR libcontacts_birthday_destroy (3),
+.BR libcontacts_block_destroy (3),
+.BR libcontacts_chat_destroy (3),
+.BR libcontacts_email_destroy (3),
+.BR libcontacts_number_destroy (3),
+.BR libcontacts_organisation_destroy (3),
+.BR libcontacts_pgpkey_destroy (3),
+.BR libcontacts_site_destroy (3),
+.BR contacts (5),
diff --git a/libcontacts_parse_contact.c b/libcontacts_parse_contact.c
index f16ee94..f081c54 100644
--- a/libcontacts_parse_contact.c
+++ b/libcontacts_parse_contact.c
@@ -129,7 +129,7 @@ appendstr(char **strp, char *new)
}
static int
-parse_coord(char *s, double *lat, double *lon)
+parse_coord(const char *s, double *lat, double *lon)
{
int withsign = 0;
int saved_errno = errno;
@@ -139,7 +139,7 @@ parse_coord(char *s, double *lat, double *lon)
withsign = (s[0] == '-' || s[0] == '+');
if (s[withsign] != '.' && !isdigit(s[withsign]))
goto bad;
- *lat = strtod(s, &s);
+ *lat = strtod(s, (char **)(void *)&s);
if (errno)
return -1;
if (!withsign && (s[0] == 'N' || s[0] == 'S')) {
@@ -155,7 +155,7 @@ parse_coord(char *s, double *lat, double *lon)
withsign = (s[0] == '-' || s[0] == '+');
if (s[withsign] != '.' && !isdigit(s[withsign]))
goto bad;
- *lon = strtod(s, &s);
+ *lon = strtod(s, (char **)(void *)&s);
if (errno)
return -1;
if (!withsign && (s[0] == 'E' || s[0] == 'W')) {
@@ -177,7 +177,7 @@ bad:
int
-libcontacts_parse_contact(char *data, struct libcontacts_contact *contact)
+libcontacts_parse_contact(char *data, struct libcontacts_contact *contactp)
{
#define TEST(S, L)\
(!strncmp((test_tmp = (S)), L, sizeof(L) - 1) &&\
@@ -208,258 +208,261 @@ libcontacts_parse_contact(char *data, struct libcontacts_contact *contact)
int state = 0;
unsigned int u;
unsigned char uc;
+ char c = 0;
- memset(contact, 0, sizeof(*contact));
+ memset(contactp, 0, sizeof(*contactp));
- for (p = data; p; p = q) {
+ for (p = data; p; p = q ? (*q = c, &q[1]) : NULL) {
q = strpbrk(p, "\n\r\f");
- if (q)
- *q++ = '\0';
+ if (q) {
+ c = *q;
+ *q = '\0';
+ }
switch ((*p == ' ' || *p == '\t') ? state : 0) {
default:
state = 0;
if (!*p);
- else if (TEST(p, "NAME") && !contact->name) {
- if (!(contact->name = strdup(getstr(p))))
+ else if (TEST(p, "NAME") && !contactp->name) {
+ if (!(contactp->name = strdup(getstr(p))))
goto fail;
- } else if (TEST(p, "FNAME") && !contact->first_name) {
- if (!(contact->first_name = strdup(getstr(p))))
+ } else if (TEST(p, "FNAME") && !contactp->first_name) {
+ if (!(contactp->first_name = strdup(getstr(p))))
goto fail;
- } else if (TEST(p, "LNAME") && !contact->last_name) {
- if (!(contact->last_name = strdup(getstr(p))))
+ } else if (TEST(p, "LNAME") && !contactp->last_name) {
+ if (!(contactp->last_name = strdup(getstr(p))))
goto fail;
- } else if (TEST(p, "FLNAME") && !contact->full_name) {
- if (!(contact->full_name = strdup(getstr(p))))
+ } else if (TEST(p, "FLNAME") && !contactp->full_name) {
+ if (!(contactp->full_name = strdup(getstr(p))))
goto fail;
- } else if (TEST(p, "NICK") && !contact->nickname) {
- if (!(contact->nickname = strdup(getstr(p))))
+ } else if (TEST(p, "NICK") && !contactp->nickname) {
+ if (!(contactp->nickname = strdup(getstr(p))))
goto fail;
} else if (TEST(p, "PHOTO")) {
- if (addstr(&contact->photos, getstr(p)))
+ if (addstr(&contactp->photos, getstr(p)))
goto fail;
} else if (TEST(p, "GROUP")) {
- if (addstr(&contact->groups, getstr(p)))
+ if (addstr(&contactp->groups, getstr(p)))
goto fail;
} else if (TEST(p, "NOTES")) {
- if (appendstr(&contact->notes, getstr(p)))
+ if (appendstr(&contactp->notes, getstr(p)))
goto fail;
} else if (!strcmp(p, "ORG:")) {
- ADD(contact->organisations);
+ ADD(contactp->organisations);
state = 1;
break;
case 1:
- if (TEST(unindent(p), "ORG") && !contact->organisations[i]->organisation) {
- if (!(contact->organisations[i]->organisation = strdup(getstr(p))))
+ if (TEST(unindent(p), "ORG") && !contactp->organisations[i]->organisation) {
+ if (!(contactp->organisations[i]->organisation = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "TITLE") && !contact->organisations[i]->title) {
- if (!(contact->organisations[i]->title = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "TITLE") && !contactp->organisations[i]->title) {
+ if (!(contactp->organisations[i]->title = strdup(getstr(p))))
goto fail;
} else {
- if (addstr(&contact->organisations[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->organisations[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "EMAIL:")) {
- ADD(contact->emails);
+ ADD(contactp->emails);
state = 2;
break;
case 2:
- if (TEST(unindent(p), "CTX") && !contact->emails[i]->context) {
- if (!(contact->emails[i]->context = strdup(getstr(p))))
+ if (TEST(unindent(p), "CTX") && !contactp->emails[i]->context) {
+ if (!(contactp->emails[i]->context = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "ADDR") && !contact->emails[i]->address) {
- if (!(contact->emails[i]->address = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "ADDR") && !contactp->emails[i]->address) {
+ if (!(contactp->emails[i]->address = strdup(getstr(p))))
goto fail;
} else {
- if (addstr(&contact->emails[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->emails[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "KEY:")) {
- ADD(contact->pgpkeys);
+ ADD(contactp->pgpkeys);
state = 3;
break;
case 3:
- if (TEST(unindent(p), "CTX") && !contact->pgpkeys[i]->context) {
- if (!(contact->pgpkeys[i]->context = strdup(getstr(p))))
+ if (TEST(unindent(p), "CTX") && !contactp->pgpkeys[i]->context) {
+ if (!(contactp->pgpkeys[i]->context = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "ID") && !contact->pgpkeys[i]->id) {
- if (!(contact->pgpkeys[i]->id = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "ID") && !contactp->pgpkeys[i]->id) {
+ if (!(contactp->pgpkeys[i]->id = strdup(getstr(p))))
goto fail;
} else {
- if (addstr(&contact->pgpkeys[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->pgpkeys[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "PHONE:")) {
- ADD(contact->numbers);
+ ADD(contactp->numbers);
state = 4;
break;
case 4:
- if (TEST(unindent(p), "CTX") && !contact->numbers[i]->context) {
- if (!(contact->numbers[i]->context = strdup(getstr(p))))
+ if (TEST(unindent(p), "CTX") && !contactp->numbers[i]->context) {
+ if (!(contactp->numbers[i]->context = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "NUMBER") && !contact->numbers[i]->number) {
- if (!(contact->numbers[i]->number = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "NUMBER") && !contactp->numbers[i]->number) {
+ if (!(contactp->numbers[i]->number = strdup(getstr(p))))
goto fail;
} else if (!strcmp(unindent(p), "MOBILE")) {
- contact->numbers[i]->is_mobile = 1;
+ contactp->numbers[i]->is_mobile = 1;
} else if (!strcmp(unindent(p), "FAX")) {
- contact->numbers[i]->is_facsimile = 1;
+ contactp->numbers[i]->is_facsimile = 1;
} else {
- if (addstr(&contact->numbers[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->numbers[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "ADDR:")) {
- ADD(contact->addresses);
+ ADD(contactp->addresses);
state = 5;
break;
case 5:
- if (TEST(unindent(p), "CTX") && !contact->addresses[i]->context) {
- if (!(contact->addresses[i]->context = strdup(getstr(p))))
+ if (TEST(unindent(p), "CTX") && !contactp->addresses[i]->context) {
+ if (!(contactp->addresses[i]->context = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "COUNTRY") && !contact->addresses[i]->country) {
- if (!(contact->addresses[i]->country = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "COUNTRY") && !contactp->addresses[i]->country) {
+ if (!(contactp->addresses[i]->country = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "C/O") && !contact->addresses[i]->care_of) {
- if (!(contact->addresses[i]->care_of = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "C/O") && !contactp->addresses[i]->care_of) {
+ if (!(contactp->addresses[i]->care_of = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "ADDR") && !contact->addresses[i]->address) {
- if (!(contact->addresses[i]->address = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "ADDR") && !contactp->addresses[i]->address) {
+ if (!(contactp->addresses[i]->address = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "CODE") && !contact->addresses[i]->postcode) {
- if (!(contact->addresses[i]->postcode = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "CODE") && !contactp->addresses[i]->postcode) {
+ if (!(contactp->addresses[i]->postcode = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "CITY") && !contact->addresses[i]->city) {
- if (!(contact->addresses[i]->city = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "CITY") && !contactp->addresses[i]->city) {
+ if (!(contactp->addresses[i]->city = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "COORD") && !contact->addresses[i]->have_coordinates) {
+ } else if (TEST(unindent(p), "COORD") && !contactp->addresses[i]->have_coordinates) {
if (!parse_coord(getstr(p),
- &contact->addresses[i]->latitude,
- &contact->addresses[i]->longitude)) {
- contact->addresses[i]->have_coordinates = 1;
+ &contactp->addresses[i]->latitude,
+ &contactp->addresses[i]->longitude)) {
+ contactp->addresses[i]->have_coordinates = 1;
} else {
- if (addstr(&contact->addresses[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->addresses[i]->unrecognised_data, unindent(p)))
goto fail;
}
} else {
- if (addstr(&contact->addresses[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->addresses[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "SITE:")) {
- ADD(contact->sites);
+ ADD(contactp->sites);
state = 6;
break;
case 6:
- if (TEST(unindent(p), "CTX") && !contact->sites[i]->context) {
- if (!(contact->sites[i]->context = strdup(getstr(p))))
+ if (TEST(unindent(p), "CTX") && !contactp->sites[i]->context) {
+ if (!(contactp->sites[i]->context = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "ADDR") && !contact->sites[i]->address) {
- if (!(contact->sites[i]->address = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "ADDR") && !contactp->sites[i]->address) {
+ if (!(contactp->sites[i]->address = strdup(getstr(p))))
goto fail;
} else {
- if (addstr(&contact->sites[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->sites[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "CHAT:")) {
- ADD(contact->chats);
+ ADD(contactp->chats);
state = 7;
break;
case 7:
- if (TEST(unindent(p), "CTX") && !contact->chats[i]->context) {
- if (!(contact->chats[i]->context = strdup(getstr(p))))
+ if (TEST(unindent(p), "CTX") && !contactp->chats[i]->context) {
+ if (!(contactp->chats[i]->context = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "SRV") && !contact->chats[i]->service) {
- if (!(contact->chats[i]->service = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "SRV") && !contactp->chats[i]->service) {
+ if (!(contactp->chats[i]->service = strdup(getstr(p))))
goto fail;
- } else if (TEST(unindent(p), "ADDR") && !contact->chats[i]->address) {
- if (!(contact->chats[i]->address = strdup(getstr(p))))
+ } else if (TEST(unindent(p), "ADDR") && !contactp->chats[i]->address) {
+ if (!(contactp->chats[i]->address = strdup(getstr(p))))
goto fail;
} else {
- if (addstr(&contact->chats[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->chats[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "BLOCK:")) {
- ADD(contact->blocks);
+ ADD(contactp->blocks);
state = 8;
break;
case 8:
- if (TEST(unindent(p), "SRV") && !contact->blocks[i]->service) {
- if (!(contact->blocks[i]->service = strdup(getstr(p))))
+ if (TEST(unindent(p), "SRV") && !contactp->blocks[i]->service) {
+ if (!(contactp->blocks[i]->service = strdup(getstr(p))))
goto fail;
- } else if (!strcmp(unindent(p), "OFF") && !contact->blocks[i]->shadow_block) {
- contact->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_OFF;
- } else if (!strcmp(unindent(p), "BUSY") && !contact->blocks[i]->shadow_block) {
- contact->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_BUSY;
- } else if (!strcmp(unindent(p), "IGNORE") && !contact->blocks[i]->shadow_block) {
- contact->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_IGNORE;
+ } else if (!strcmp(unindent(p), "OFF") && !contactp->blocks[i]->shadow_block) {
+ contactp->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_OFF;
+ } else if (!strcmp(unindent(p), "BUSY") && !contactp->blocks[i]->shadow_block) {
+ contactp->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_BUSY;
+ } else if (!strcmp(unindent(p), "IGNORE") && !contactp->blocks[i]->shadow_block) {
+ contactp->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_IGNORE;
} else if (!strcmp(unindent(p), "EXPLICIT")) {
- contact->blocks[i]->explicit = 1;
- } else if (TEST(unindent(p), "ASK") && !contact->blocks[i]->soft_unblock && (t = gettime(p))) {
- contact->blocks[i]->soft_unblock = t;
- } else if (TEST(unindent(p), "REMOVE") && !contact->blocks[i]->hard_unblock && (t = gettime(p))) {
- contact->blocks[i]->hard_unblock = t;
+ contactp->blocks[i]->explicit = 1;
+ } else if (TEST(unindent(p), "ASK") && !contactp->blocks[i]->soft_unblock && (t = gettime(p))) {
+ contactp->blocks[i]->soft_unblock = t;
+ } else if (TEST(unindent(p), "REMOVE") && !contactp->blocks[i]->hard_unblock && (t = gettime(p))) {
+ contactp->blocks[i]->hard_unblock = t;
} else {
- if (addstr(&contact->blocks[i]->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->blocks[i]->unrecognised_data, unindent(p)))
goto fail;
}
break;
- } else if (!strcmp(p, "BIRTH:") && !contact->birthday) {
- contact->birthday = calloc(1, sizeof(*contact->birthday));
- if (!contact->birthday)
+ } else if (!strcmp(p, "BIRTH:") && !contactp->birthday) {
+ contactp->birthday = calloc(1, sizeof(*contactp->birthday));
+ if (!contactp->birthday)
goto fail;
state = 9;
break;
case 9:
- if (TEST(unindent(p), "YEAR") && !contact->birthday->year && (u = getposuint(p))) {
- contact->birthday->year = u;
- } else if (TEST(unindent(p), "MONTH") && !contact->birthday->month && (uc = getposuchar(p))) {
- contact->birthday->month = uc;
- } else if (TEST(unindent(p), "DAY") && !contact->birthday->day && (uc = getposuchar(p))) {
- contact->birthday->day = uc;
+ if (TEST(unindent(p), "YEAR") && !contactp->birthday->year && (u = getposuint(p))) {
+ contactp->birthday->year = u;
+ } else if (TEST(unindent(p), "MONTH") && !contactp->birthday->month && (uc = getposuchar(p))) {
+ contactp->birthday->month = uc;
+ } else if (TEST(unindent(p), "DAY") && !contactp->birthday->day && (uc = getposuchar(p))) {
+ contactp->birthday->day = uc;
} else if (!strcmp(unindent(p), "EARLY")) {
- contact->birthday->before_on_common = 1;
+ contactp->birthday->before_on_common = 1;
} else {
- if (addstr(&contact->birthday->unrecognised_data, unindent(p)))
+ if (addstr(&contactp->birthday->unrecognised_data, unindent(p)))
goto fail;
}
break;
} else if (!strcmp(p, "ICE")) {
- contact->in_case_of_emergency = 1;
+ contactp->in_case_of_emergency = 1;
- } else if (!strcmp(p, "NPERSON") && !contact->gender) {
- contact->gender = LIBCONTACTS_NOT_A_PERSON;
+ } else if (!strcmp(p, "NPERSON") && !contactp->gender) {
+ contactp->gender = LIBCONTACTS_NOT_A_PERSON;
- } else if (!strcmp(p, "MALE") && !contact->gender) {
- contact->gender = LIBCONTACTS_MALE;
+ } else if (!strcmp(p, "MALE") && !contactp->gender) {
+ contactp->gender = LIBCONTACTS_MALE;
- } else if (!strcmp(p, "FEMALE") && !contact->gender) {
- contact->gender = LIBCONTACTS_FEMALE;
+ } else if (!strcmp(p, "FEMALE") && !contactp->gender) {
+ contactp->gender = LIBCONTACTS_FEMALE;
} else {
- if (addstr(&contact->unrecognised_data, p))
+ if (addstr(&contactp->unrecognised_data, p))
goto fail;
}
}
@@ -468,8 +471,8 @@ libcontacts_parse_contact(char *data, struct libcontacts_contact *contact)
return 0;
fail:
- libcontacts_contact_destroy(contact);
- memset(contact, 0, sizeof(*contact));
+ libcontacts_contact_destroy(contactp);
+ memset(contactp, 0, sizeof(*contactp));
return -1;
#undef TEST
diff --git a/libcontacts_pgpkey_destroy.3 b/libcontacts_pgpkey_destroy.3
new file mode 100644
index 0000000..2e88507
--- /dev/null
+++ b/libcontacts_pgpkey_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_PGP_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_pgp_destroy \- Deallocate memory for a contact PGP-key fingerprint entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_pgp_destroy(struct libcontacts_pgp *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_pgp_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/libcontacts_same_number.3 b/libcontacts_same_number.3
new file mode 100644
index 0000000..3b30a89
--- /dev/null
+++ b/libcontacts_same_number.3
@@ -0,0 +1,74 @@
+.TH LIBCONTACTS_SAME_NUMBER 3 LIBCONTACTS
+.SH NAME
+libcontacts_same_number \- Save a contact
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_same_number(const char *\fIa\fP, const char *\fIa_country\fP, const char *\fIb\fP, const char *\fIb_country\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_same_number ()
+function checks whether the telephone numbers specified
+in the
+.I a
+and
+.I b
+parameters are the same number.
+.PP
+The country calling code for
+.I a
+and
+.I b
+may be specified in the
+.I a_country
+and
+.I b_country
+parameters respectively. If the empty string is specified
+as a country calling code, it is treated as unspecified.
+.B \(dq00\(dq
+will be added automatically if it, or its alternative
+.B \(dq+\(dq
+is missing.
+
+.SH RETURN VALUE
+The
+.BR libcontacts_same_number ()
+function returns 1 or 0 upon successful completion;
+otherwise -1 is returned and
+.I errno
+is set appropriately to indicate the error.
+If the returned value is 1, the numbers match,
+if the returned value is 0, the numbers do not match.
+
+.SH ERRORS
+The
+.BR libcontacts_same_number ()
+function will fail if:
+.TP
+.B EINVAL
+The
+.I a
+or
+.I b
+is
+.I NULL
+or the empty string.
+.PP
+The
+.BR libcontacts_same_number ()
+function may fail for any reason specified for the
+.BR malloc (3)
+function.
+
+.SH FUTURE DIRECTIONS
+This function may be removed in the future.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7)
diff --git a/libcontacts_save_contact.3 b/libcontacts_save_contact.3
new file mode 100644
index 0000000..161e190
--- /dev/null
+++ b/libcontacts_save_contact.3
@@ -0,0 +1,78 @@
+.TH LIBCONTACTS_SAVE_CONTACT 3 LIBCONTACTS
+.SH NAME
+libcontacts_save_contact \- Save a contact
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_save_contact(struct libcontacts_contact *\fIcontact\fP, const struct passwd *\fIuser\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_save_contact ()
+function saves the contact entry that is specified in the
+.I contact
+parameter.
+.PP
+If
+.I contact->id
+is
+.I NULL
+an ID will be assigned to it, and stored in
+.IR contact->id .
+If the call is successful, the caller must manually
+free this ID, if the function
+assignee's it, using the
+.BR free (3)
+function.
+.PP
+.I user
+shall be the user's entry in the password database (not
+the shadow database). This is used for the get user's
+home directory.
+
+.SH RETURN VALUE
+The
+.BR libcontacts_save_contact ()
+function returns 0 upon successful completion;
+otherwise -1 is returned and
+.I errno
+is set appropriately to indicate the error.
+
+.SH ERRORS
+The
+.BR libcontacts_save_contact ()
+function will fail if:
+.TP
+.B 0
+The file it saves contains a NUL byte.
+.PP
+The
+.BR libcontacts_save_contact ()
+function may fail for any reason specified for the
+.BR libcontacts_format_contact (3),
+.BR libcontacts_get_path (3),
+.BR malloc (3),
+.BR open (3)
+(other than
+.IR EEXIST ),
+.BR mkdir (3)
+(other than
+.IR EEXIST ),
+.BR write (3),
+.BR fsync (3),
+and
+.BR rename (3)
+functions.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_load_contact (3),
+.BR libcontacts_loads_contact (3),
+.BR libcontacts_contact_destroy (3),
+.BR libcontacts_format_contact (3)
diff --git a/libcontacts_save_contact.c b/libcontacts_save_contact.c
index b373a46..6c653f9 100644
--- a/libcontacts_save_contact.c
+++ b/libcontacts_save_contact.c
@@ -32,7 +32,7 @@ int
libcontacts_save_contact(struct libcontacts_contact *contact, const struct passwd *user)
{
char *data = NULL, *path = NULL, *tmppath = NULL;
- int oflags = O_WRONLY | O_CREAT | O_TRUNC;
+ int oflags = O_WRONLY | O_CREAT | O_TRUNC, newid = 0;
int fd = -1, saved_errno = errno, dirs_created = 0;
ssize_t r;
size_t p, n, num = 0;
@@ -49,10 +49,12 @@ libcontacts_save_contact(struct libcontacts_contact *contact, const struct passw
contact->id = strdup("unnamed");
if (!contact->id)
goto fail;
+ newid = 1;
} else {
contact->id = strdup(contact->name);
if (!contact->id)
goto fail;
+ newid = 1;
for (p = 0; contact->id[p]; p++) {
if (isalpha(contact->id[p]))
contact->id[p] = (char)tolower(contact->id[p]);
@@ -147,6 +149,10 @@ fail:
free(path);
free(tmppath);
free(basenam);
+ if (newid) {
+ free(contact->id);
+ contact->id = NULL;
+ }
errno = saved_errno;
return -1;
}
diff --git a/libcontacts_site_destroy.3 b/libcontacts_site_destroy.3
new file mode 100644
index 0000000..5e4a0ac
--- /dev/null
+++ b/libcontacts_site_destroy.3
@@ -0,0 +1,34 @@
+.TH LIBCONTACTS_SITE_DESTROY 3 LIBCONTACTS
+.SH NAME
+libcontacts_site_destroy \- Deallocate memory for a contact Internet site entry
+.SH SYNOPSIS
+.nf
+#include <libcontacts.h>
+
+int libcontacts_site_destroy(struct libcontacts_site *\fIentry\fP);
+.fi
+.PP
+Link with
+.IR -lcontacts .
+
+.SH DESCRIPTION
+The
+.BR libcontacts_site_destroy ()
+function deallocates the memory stored in
+.IR *entry .
+The caller must manually call
+.BR free (3)
+on the pointer
+.I entry
+afterwards if it a freeable pointer.
+
+.SH RETURN VALUE
+None.
+
+.SH ERRORS
+None.
+
+.SH SEE ALSO
+.BR libcontacts.h (0),
+.BR libcontacts (7),
+.BR libcontacts_contact_destroy (3)
diff --git a/test.c b/test.c
index 8b694d3..a7dae8b 100644
--- a/test.c
+++ b/test.c
@@ -99,6 +99,7 @@ main(void)
/* TODO test libcontacts_load_contacts */
/* TODO test libcontacts_format_contact */
/* TODO test libcontacts_save_contact */
+ /* TODO test libcontacts_contact_destroy */
/* TODO check for memory leaks */
/* TODO check for file descriptor leaks */