aboutsummaryrefslogblamecommitdiffstats
path: root/common.h
blob: d3f0f3e25861f20f3bac4c3ac49b5f094fbde700 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                         



                                          



                          

                 
 


                    


                       


                                           


                                                                              

                      
                                                                                                                             






                            

                                                                        

                                    
                                                                        

                                    
                                                                       

                                  
                                                                   

                                                                  
                                                                        

                           
                                                                     












                                      
                                                                          










                                    
                                                                  

              
                                                                   


                                                                               
                                                                        


                                                                                    
                                                                   




                                                      
                                                                     


                                                          
                                                                

                                       
                                                                    


                                             
                                                                                                                                    




                                                   

                                                    





                                                          

                                                      












                                                                    
                                                                                               

















                                                                                                    

                                                                    










                                                                       

                                                                 






                                                                                                            

                                                         





                                                                          
                                                   




                                                       






























































































































































































                                                                                                    
/* See LICENSE file for copyright and license details. */
#ifdef MULTICALL_BINARY
# define LIBSIMPLY_CONFIG_MULTICALL_BINARY
#endif

#include <libcontacts.h>
#include <libsimple.h>
#include <libsimple-arg.h>

#include <math.h>


#ifndef BUFSIZ
# define BUFSIZ 4096
#endif


/* common-birthday.c */
#if defined(__GNUC__) || defined(__clang__)
__attribute__((__pure__))
#endif
int get_age(struct libcontacts_birthday *bday, const struct tm *now);
void print_birthdate(struct libcontacts_birthday *bday, const struct tm *now);
void print_birthday(struct libcontacts_birthday *bday, const struct tm *now);

/* common-address.c */
int parse_coord(const char *s, double *lat, double *lat_min, double *lat_max, double *lon, double *lon_min, double *lon_max);



#ifndef LIST_BOOL_PARAMS
# define LIST_BOOL_PARAMS(X)
#endif


#define X_SET_USAGE_UPPER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	"[-"UPPERS" old-"DISPLAY"] "

#define X_SET_USAGE_LOWER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	"[-"LOWERS" new-"DISPLAY"] "

#define X_SET_USAGE_BOOL(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	"[-"UPPERS" | -"LOWERS"] "

#define X_SET_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	char *VAR = NULL, *lookup_##VAR = NULL, *old_##VAR = NULL;

#define X_SET_BOOL_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	int set_##VAR = -1;

#define X_SET_ARGPARSE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	case UPPERC:\
		add = 0;\
		if (lookup_##VAR)\
			usage();\
		lookup_##VAR = ARG();\
		break;\
	case LOWERC:\
		edit = 1;\
		if (VAR)\
			usage();\
		VAR = ARG();\
		break;

#define X_SET_BOOL_ARGPARSE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	case UPPERC:\
		if (set_##VAR >= 0)\
			usage();\
		set_##VAR = 0;\
		break;\
	case LOWERC:\
		if (set_##VAR >= 0)\
			usage();\
		set_##VAR = 1;\
		break;

#define X_SET_LOWER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	LOWERS

#define X_SET_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	if (lookup_##VAR && strcmpnul(contact.CATEGORY[i]->VAR, lookup_##VAR))\
		continue;

#define X_SET_BOOL_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	if (remove && set_##VAR >= 0 && contact.CATEGORY[i]->is_##VAR != set_##VAR)\
		continue;

#define X_SET_CHANGE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	if (VAR) {\
		old_##VAR = contact.CATEGORY[i]->VAR;\
		contact.CATEGORY[i]->VAR = VAR;\
	}

#define X_SET_BOOL_SET(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	if (set_##VAR >= 0)\
		contact.CATEGORY[i]->is_##VAR = set_##VAR;

#define X_SET_ADD(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	contact.CATEGORY[i]->VAR = VAR;

#define X_SET_RESTORE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	contact.CATEGORY[i]->VAR = old_##VAR;

#define IMPLEMENT_SET_ON_LIST(CAT)\
	USAGE(LIST_PARAMS(X_SET_USAGE_UPPER)LIST_BOOL_PARAMS(X_SET_USAGE_BOOL)"("LIST_PARAMS(X_SET_USAGE_LOWER)"| -u) contact-id");\
	\
	int\
	main(int argc, char *argv[])\
	{\
		int add = 1, edit = 0, remove = 0;\
		LIST_PARAMS(X_SET_PARAMS)\
		LIST_BOOL_PARAMS(X_SET_BOOL_PARAMS)\
		struct passwd *user;\
		struct libcontacts_contact contact;\
		struct libcontacts_##CAT **r = NULL, **w;\
		size_t i;\
		\
		ARGBEGIN {\
		LIST_PARAMS(X_SET_ARGPARSE)\
		LIST_BOOL_PARAMS(X_SET_BOOL_ARGPARSE)\
		case 'u':\
			remove = 1;\
			break;\
		default:\
			usage();\
		} ARGEND;\
		\
		if (argc != 1 || !*argv[0] || strchr(argv[0], '/'))\
			usage();\
		\
		if (remove == edit) {\
			if (edit)\
				usage();\
			eprintf("at least one of -"LIST_PARAMS(X_SET_LOWER)"u is required\n");\
		}\
		\
		if (add)\
			edit = 0;\
		\
		errno = 0;\
		user = getpwuid(getuid());\
		if (!user)\
			eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");\
		\
		if (libcontacts_load_contact(argv[0], &contact, user)) {\
			eprintf("libcontacts_load_contact %s: %s\n", argv[0],\
			        errno ? strerror(errno) : "contact file is malformatted");\
		}\
		\
		i = 0;\
		if ((edit || remove) && contact.CATEGORY) {\
			for (; contact.CATEGORY[i]; i++) {\
				LIST_PARAMS(X_SET_LOOKUP)\
				LIST_BOOL_PARAMS(X_SET_BOOL_LOOKUP)\
				break;\
			}\
			if (!contact.CATEGORY[i]) {\
				libcontacts_contact_destroy(&contact);\
				return 0;\
			} else if (!edit) {\
				r = &contact.CATEGORY[i];\
				libcontacts_##CAT##_destroy(*r);\
				free(*r);\
				for (w = r++; (*w++ = *r++););\
			} else {\
				LIST_PARAMS(X_SET_CHANGE)\
				LIST_BOOL_PARAMS(X_SET_BOOL_SET)\
			}\
		} else if (!edit && !remove) {\
			if (contact.CATEGORY)\
				for (; contact.CATEGORY[i]; i++);\
			contact.CATEGORY = erealloc(contact.CATEGORY, (i + 2) * sizeof(*contact.CATEGORY));\
			contact.CATEGORY[i + 1] = NULL;\
			contact.CATEGORY[i] = ecalloc(1, sizeof(**contact.CATEGORY));\
			LIST_PARAMS(X_SET_ADD)\
			LIST_BOOL_PARAMS(X_SET_BOOL_SET)\
		}\
		\
		if (libcontacts_save_contact(&contact, user))\
			eprintf("libcontacts_save_contact %s:", argv[0]);\
		\
		if (!r) {\
			LIST_PARAMS(X_SET_RESTORE)\
		}\
		\
		libcontacts_contact_destroy(&contact);\
		return 0;\
	}


#define X_GET_USAGE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	"[-"LOWERS" "DISPLAY"] "

#define X_GET_UPPER(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	UPPERS

#define X_GET_PARAMS(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	int display_##VAR = 0;\
	const char *lookup_##VAR = NULL;

#define X_GET_ARGPARSE(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	case LOWERC:\
		if (lookup_##VAR)\
			usage();\
		lookup_##VAR = ARG();\
		break;\
	case UPPERC:\
		fields += !display_##VAR;\
		display_##VAR = 1;\
		break;

#define X_GET_AUTO_DISPLAY(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	fields += display_##VAR = !lookup_##VAR;

#define X_GET_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	if (lookup_##VAR && strcmpnul(elem->VAR, lookup_##VAR))\
		continue;

#define X_GET_FULL_LOOKUP(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	lookup_##VAR && 

#define X_GET_DISPLAY(UPPERC, UPPERS, LOWERC, LOWERS, VAR, DISPLAY)\
	if (display_##VAR) {\
		fields_ -= 1;\
		printf("%s%s", elem->VAR, fields_ ? ": " : "\n");\
	}

#define IMPLEMENT_GET_ON_LIST(CAT)\
	USAGE(LIST_PARAMS(X_GET_USAGE)"[-"LIST_PARAMS(X_GET_UPPER)"] contact-id ..."); \
	\
	int\
	main(int argc, char *argv[])\
	{\
		LIST_PARAMS(X_GET_PARAMS)\
		struct passwd *user;\
		struct libcontacts_contact contact;\
		struct libcontacts_##CAT **elems, *elem;\
		int ret = 0, fields = 0, fields_;\
		size_t i; \
		\
		ARGBEGIN {\
		LIST_PARAMS(X_GET_ARGPARSE)\
		default:\
			usage();\
		} ARGEND;\
		\
		if (!argc)\
			usage();\
		\
		if (!fields) {\
			LIST_PARAMS(X_GET_AUTO_DISPLAY)\
		}\
		\
		for (i = 0; argv[i]; i++)\
			if (!*argv[i] || strchr(argv[i], '/'))\
				usage();\
		\
		errno = 0;\
		user = getpwuid(getuid());\
		if (!user)\
			eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");\
		\
		for (; *argv; argv++) {\
			if (libcontacts_load_contact(*argv, &contact, user)) {\
				weprintf("libcontacts_load_contact %s: %s\n", *argv,\
				         errno ? strerror(errno) : "contact file is malformatted");\
				ret = 1;\
				continue;\
			}\
			if ((elems = contact.CATEGORY)) {\
				for (; (elem = *elems); elems++) {\
					LIST_PARAMS(X_GET_LOOKUP)\
					if (LIST_PARAMS(X_GET_FULL_LOOKUP) !fields) {\
						printf("%s\n", *argv);\
						continue;\
					}\
					if (argc > 1)\
						printf("%s: ", *argv);\
					fields_ = fields;\
					LIST_PARAMS(X_GET_DISPLAY)\
				}\
			}\
			libcontacts_contact_destroy(&contact);\
		}\
		\
		if (fflush(stdout) || ferror(stdout) || fclose(stdout))\
			eprintf("printf:");\
		return ret;\
	}


#define X_FIND_USAGE(LOWERC, LOWERS, VAR, DISPLAY)\
	"[-"LOWERS" "DISPLAY"] "

#define X_FIND_PARAMS(LOWERC, LOWERS, VAR, DISPLAY)\
	const char *VAR = NULL;

#define X_FIND_ARGPARSE(LOWERC, LOWERS, VAR, DISPLAY)\
	case LOWERC:\
		if (VAR)\
			usage();\
		VAR = ARG();\
		break;

#define X_FIND_LOOKUP(LOWERC, LOWERS, VAR, DISPLAY)\
	if (VAR && strcmpnul(elem->VAR, VAR))\
		continue;

#ifdef SUBCATEGORY
# define PRINT_PREFIX_LIST(DATUM)\
	if (elem->SUBCATEGORY && !SUBCATEGORY)\
		printf("%s (%s: %s)\n", contacts[i]->id, elem->SUBCATEGORY, elem->DATUM);\
	else
# define PRINT_PREFIX_LOOKUP(DATUM)\
	if (elem->SUBCATEGORY && !SUBCATEGORY)\
		printf("%s (%s)\n", contacts[i]->id, elem->SUBCATEGORY);\
	else
#else
# define PRINT_PREFIX_LIST(DATUM)
# define PRINT_PREFIX_LOOKUP(DATUM)
#endif

#define IMPLEMENT_FIND_ON_LIST(CAT, DATUM, DISPLAY)\
	USAGE(LIST_PARAMS(X_FIND_USAGE)"(-L | "DISPLAY")");\
	\
	int\
	main(int argc, char *argv[])\
	{\
		int list = 0;\
		LIST_PARAMS(X_FIND_PARAMS)\
		struct passwd *user;\
		struct libcontacts_contact **contacts;\
		struct libcontacts_##CAT **elems, *elem;\
		size_t i;\
		\
		ARGBEGIN {\
		LIST_PARAMS(X_FIND_ARGPARSE)\
		case 'L':\
			list = 1;\
			break;\
		default:\
			usage();\
		} ARGEND;\
		\
		if (argc != 1 - list)\
			usage();\
		\
		errno = 0;\
		user = getpwuid(getuid());\
		if (!user)\
			eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");\
		\
		if (libcontacts_load_contacts(&contacts, user, 1))\
			eprintf("libcontacts_load_contacts:");\
		for (i = 0; contacts[i]; i++) {\
			if ((elems = contacts[i]->CATEGORY)) {\
				for (; (elem = *elems); elems++) {\
					if (!elem->DATUM)\
						continue;\
					LIST_PARAMS(X_FIND_LOOKUP)\
					if (list) {\
						PRINT_PREFIX_LIST(DATUM)\
						printf("%s (%s)\n", contacts[i]->id, elem->DATUM);\
					} else if (!strcmp(elem->DATUM, argv[0])) {\
						PRINT_PREFIX_LOOKUP(DATUM)\
						printf("%s\n", contacts[i]->id);\
					}\
				}\
			}\
			libcontacts_contact_destroy(contacts[i]);\
			free(contacts[i]);\
		}\
		free(contacts);\
		\
		if (fflush(stdout) || ferror(stdout) || fclose(stdout))\
			eprintf("printf:");\
		\
		return 0;\
	}