X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fserv_vcard.c;h=ba292dfebbfff248efae9d45c2ee31f8767401b9;hb=01cc19a4c2da27b4db0e980ccd3ca54d834319c8;hp=ed31981b3ec479edb3001597cd9327b325ea464b;hpb=49548fc3d014f7934231cce0e57e8a3e69dc3683;p=citadel.git diff --git a/citadel/serv_vcard.c b/citadel/serv_vcard.c index ed31981b3..ba292dfeb 100644 --- a/citadel/serv_vcard.c +++ b/citadel/serv_vcard.c @@ -15,6 +15,12 @@ */ #define VCARD_EXT_FORMAT "Citadel vCard: personal card for %s at %s" +/* + * Citadel will accept either text/vcard or text/x-vcard as the MIME type + * for a vCard. The following definition determines which one it *generates* + * when serializing. + */ +#define VCARD_MIME_TYPE "text/x-vcard" #include "sysdep.h" #include @@ -43,12 +49,10 @@ #include #include "citadel.h" #include "server.h" -#include "sysdep_decls.h" #include "citserver.h" #include "support.h" #include "config.h" #include "control.h" -#include "serv_extensions.h" #include "room_ops.h" #include "user_ops.h" #include "policy.h" @@ -61,6 +65,11 @@ #include "serv_ldap.h" #include "serv_vcard.h" + +#include "ctdl_module.h" + + + /* * set global flag calling for an aide to validate new users */ @@ -190,7 +199,7 @@ void cmd_igab(char *argbuf) { CtdlDirectoryInit(); /* We want *all* vCards in this room */ - CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/x-vcard", + CtdlForEachMessage(MSGS_ALL, 0, NULL, "^[Tt][Ee][Xx][Tt]/.*[Vv][Cc][Aa][Rr][Dd]$", NULL, vcard_add_to_directory, NULL); getroom(&CC->room, hold_rm); /* return to saved room */ @@ -204,33 +213,40 @@ void cmd_igab(char *argbuf) { * See if there is a valid Internet address in a vCard to use for outbound * Internet messages. If there is, stick it in the buffer. */ -void extract_primary_inet_email(char *emailaddrbuf, size_t emailaddrbuf_len, struct vCard *v) { +void extract_inet_email_addrs(char *emailaddrbuf, size_t emailaddrbuf_len, + char *secemailaddrbuf, size_t secemailaddrbuf_len, + struct vCard *v, int local_addrs_only) { char *s, *addr; - int continue_searching = 1; int instance = 0; + int saved_instance = 0; /* Go through the vCard searching for *all* instances of * the "email;internet" key */ - do { - s = vcard_get_prop(v, "email;internet", 0, instance++, 0); - if (s != NULL) { - continue_searching = 1; - addr = strdup(s); - striplt(addr); - if (strlen(addr) > 0) { - if (IsDirectory(addr)) { - continue_searching = 0; - safestrncpy(emailaddrbuf, addr, - emailaddrbuf_len); + while (s = vcard_get_prop(v, "email;internet", 0, instance++, 0), s != NULL) { + addr = strdup(s); + striplt(addr); + if (strlen(addr) > 0) { + if ( (IsDirectory(addr, 1)) || + (!local_addrs_only) ) { + ++saved_instance; + if ((saved_instance == 1) && (emailaddrbuf != NULL)) { + safestrncpy(emailaddrbuf, addr, emailaddrbuf_len); + } + else if ((saved_instance == 2) && (secemailaddrbuf != NULL)) { + safestrncpy(secemailaddrbuf, addr, secemailaddrbuf_len); + } + else if ((saved_instance > 2) && (secemailaddrbuf != NULL)) { + if ( (strlen(addr) + strlen(secemailaddrbuf) + 2) + < secemailaddrbuf_len ) { + strcat(secemailaddrbuf, "|"); + strcat(secemailaddrbuf, addr); + } } } - free(addr); - } - else { - continue_searching = 0; } - } while(continue_searching); + free(addr); + } } @@ -338,6 +354,11 @@ int vcard_upload_beforesave(struct CtdlMessage *msg) { if (v == NULL) return(0); /* no vCards were found in this message */ + /* If users cannot create their own accounts, they cannot re-register either. */ + if ( (yes_my_citadel_config) && (config.c_disable_newu) && (CC->user.axlevel < 6) ) { + return(1); + } + s = vcard_get_prop(v, "FN", 0, 0, 0); if (s) lprintf(CTDL_DEBUG, "vCard beforesave hook running for <%s>\n", s); @@ -434,7 +455,7 @@ int vcard_upload_beforesave(struct CtdlMessage *msg) { if (ser != NULL) { msg->cm_fields['M'] = realloc(msg->cm_fields['M'], strlen(ser) + 1024); sprintf(msg->cm_fields['M'], - "Content-type: text/x-vcard" + "Content-type: " VCARD_MIME_TYPE "\r\n\r\n%s\r\n", ser); free(ser); } @@ -474,8 +495,10 @@ int vcard_upload_aftersave(struct CtdlMessage *msg) { linelen = strcspn(ptr, "\n"); if (linelen == 0) return(0); /* end of headers */ - if (!strncasecmp(ptr, "Content-type: text/x-vcard", 26)) { - /* Bingo! The user is uploading a new vCard, so + if ( (!strncasecmp(ptr, "Content-type: text/x-vcard", 26)) + || (!strncasecmp(ptr, "Content-type: text/vcard", 24)) ) { + /* + * Bingo! The user is uploading a new vCard, so * copy it to the Global Address Book room. */ @@ -484,7 +507,9 @@ int vcard_upload_aftersave(struct CtdlMessage *msg) { /* Store our Internet return address in memory */ v = vcard_load(msg->cm_fields['M']); - extract_primary_inet_email(CC->cs_inet_email, sizeof CC->cs_inet_email, v); + extract_inet_email_addrs(CC->cs_inet_email, sizeof CC->cs_inet_email, + CC->cs_inet_other_emails, sizeof CC->cs_inet_other_emails, + v, 1); extract_friendly_name(CC->cs_inet_fn, sizeof CC->cs_inet_fn, v); vcard_free(v); @@ -548,7 +573,7 @@ struct vCard *vcard_get_user(struct ctdluser *u) { /* We want the last (and probably only) vcard in this room */ VCmsgnum = (-1); - CtdlForEachMessage(MSGS_LAST, 1, NULL, "text/x-vcard", + CtdlForEachMessage(MSGS_LAST, 1, NULL, "^[Tt][Ee][Xx][Tt]/.*[Vv][Cc][Aa][Rr][Dd]$", NULL, vcard_gu_backend, (void *)&VCmsgnum ); getroom(&CC->room, hold_rm); /* return to saved room */ @@ -594,7 +619,7 @@ void vcard_write_user(struct ctdluser *u, struct vCard *v) { * is going to notice what we're trying to do, and delete the old vCard. */ CtdlWriteObject(USERCONFIGROOM, /* which room */ - "text/x-vcard", /* MIME type */ + VCARD_MIME_TYPE,/* MIME type */ temp, /* temp file */ u, /* which user */ 0, /* not binary */ @@ -630,6 +655,12 @@ void cmd_regi(char *argbuf) { return; } + /* If users cannot create their own accounts, they cannot re-register either. */ + if ( (config.c_disable_newu) && (CC->user.axlevel < 6) ) { + cprintf("%d Self-service registration is not allowed here.\n", + ERROR + HIGHER_ACCESS_REQUIRED); + } + my_vcard = vcard_get_user(&CC->user); strcpy(tmpaddr, ""); strcpy(tmpcity, ""); @@ -738,6 +769,7 @@ void cmd_greg(char *argbuf) extract_token(buf, adr, 6, ';', sizeof buf); cprintf("%s\n", buf); /* country */ cprintf("000\n"); + vcard_free(v); } @@ -824,10 +856,10 @@ int vcard_extract_from_network(struct CtdlMessage *msg, char *target_room) { linelen = strcspn(ptr, "\n"); if (linelen == 0) return(0); /* end of headers */ - if (!strncasecmp(ptr, "Content-type: text/x-vcard", 26)) { - /* It's a vCard. Add it to the directory. */ - vcard_extract_internet_addresses(msg, - CtdlDirectoryAddUser); + if ( (!strncasecmp(ptr, "Content-type: text/x-vcard", 26)) + || (!strncasecmp(ptr, "Content-type: text/vcard", 24)) ) { + /* It's a vCard. Add it to the directory. */ + vcard_extract_internet_addresses(msg, CtdlDirectoryAddUser); return(0); } @@ -864,11 +896,10 @@ void vcard_delete_remove(char *room, long msgnum) { linelen = strcspn(ptr, "\n"); if (linelen == 0) goto EOH; - if (!strncasecmp(ptr, "Content-type: text/x-vcard", 26)) { - /* Bingo! A vCard is being deleted. - */ - vcard_extract_internet_addresses(msg, - CtdlDirectoryDelUser); + if ( (!strncasecmp(ptr, "Content-type: text/x-vcard", 26)) + || (!strncasecmp(ptr, "Content-type: text/vcard", 24)) ) { + /* Bingo! A vCard is being deleted. */ + vcard_extract_internet_addresses(msg, CtdlDirectoryDelUser); #ifdef HAVE_LDAP ctdl_vcard_to_ldap(msg, V2L_DELETE); #endif @@ -898,6 +929,114 @@ void cmd_gvsn(char *argbuf) } +/* + * Get Valid Email Addresses + */ +void cmd_gvea(char *argbuf) +{ + int num_secondary_emails = 0; + int i; + char buf[256]; + + if (CtdlAccessCheck(ac_logged_in)) return; + + cprintf("%d valid email addresses:\n", LISTING_FOLLOWS); + if (strlen(CC->cs_inet_email) > 0) { + cprintf("%s\n", CC->cs_inet_email); + } + if (strlen(CC->cs_inet_other_emails) > 0) { + num_secondary_emails = num_tokens(CC->cs_inet_other_emails, '|'); + for (i=0; ics_inet_other_emails,i,'|',sizeof CC->cs_inet_other_emails); + cprintf("%s\n", buf); + } + } + cprintf("000\n"); +} + + + + +/* + * Callback function for cmd_dvca() that hunts for vCard content types + * and outputs any email addresses found within. + */ +void dvca_mime_callback(char *name, char *filename, char *partnum, char *disp, + void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, + void *cbuserdata) { + + struct vCard *v; + char displayname[256]; + int displayname_len; + char emailaddr[256]; + int i; + int has_commas = 0; + + if ( (strcasecmp(cbtype, "text/vcard")) && (strcasecmp(cbtype, "text/x-vcard")) ) { + return; + } + + v = vcard_load(content); + if (v == NULL) return; + + extract_friendly_name(displayname, sizeof displayname, v); + extract_inet_email_addrs(emailaddr, sizeof emailaddr, NULL, 0, v, 0); + + displayname_len = strlen(displayname); + for (i=0; i\n", + (has_commas ? "\"" : ""), + displayname, + (has_commas ? "\"" : ""), + emailaddr + ); + + vcard_free(v); +} + + +/* + * Back end callback function for cmd_dvca() + * + * It's basically just passed a list of message numbers, which we're going + * to fetch off the disk and then pass along to the MIME parser via another + * layer of callback... + */ +void dvca_callback(long msgnum, void *userdata) { + struct CtdlMessage *msg = NULL; + + msg = CtdlFetchMessage(msgnum, 1); + if (msg == NULL) return; + mime_parser(msg->cm_fields['M'], + NULL, + *dvca_mime_callback, /* callback function */ + NULL, NULL, + NULL, /* user data */ + 0 + ); + CtdlFreeMessage(msg); +} + + +/* + * Dump VCard Addresses + */ +void cmd_dvca(char *argbuf) +{ + if (CtdlAccessCheck(ac_logged_in)) return; + + cprintf("%d addresses:\n", LISTING_FOLLOWS); + CtdlForEachMessage(MSGS_ALL, 0, NULL, NULL, NULL, dvca_callback, NULL); + cprintf("000\n"); +} + + /* * Query Directory */ @@ -959,9 +1098,8 @@ void check_get(void) { lprintf(CTDL_INFO, "sending 500 REJECT noone here by that name: %s\n", internet_addr); } - if (rcpt != NULL) free (rcpt); + if (rcpt != NULL) free_recipients(rcpt); } -/// CC->kill_me = 1; } void check_get_greeting(void) { @@ -1007,7 +1145,9 @@ void vcard_session_login_hook(void) { struct vCard *v = NULL; v = vcard_get_user(&CC->user); - extract_primary_inet_email(CC->cs_inet_email, sizeof CC->cs_inet_email, v); + extract_inet_email_addrs(CC->cs_inet_email, sizeof CC->cs_inet_email, + CC->cs_inet_other_emails, sizeof CC->cs_inet_other_emails, + v, 1); extract_friendly_name(CC->cs_inet_fn, sizeof CC->cs_inet_fn, v); vcard_free(v); @@ -1101,7 +1241,7 @@ void store_this_ha(struct addresses_to_be_filed *aptr) { /* First remove any addresses we already have in the address book */ usergoto(aptr->roomname, 0, 0, NULL, NULL); - CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/x-vcard", NULL, + CtdlForEachMessage(MSGS_ALL, 0, NULL, "^[Tt][Ee][Xx][Tt]/.*[Vv][Cc][Aa][Rr][Dd]$", NULL, strip_addresses_already_have, aptr->collected_addresses); if (strlen(aptr->collected_addresses) > 0) @@ -1123,7 +1263,7 @@ void store_this_ha(struct addresses_to_be_filed *aptr) { if (ser != NULL) { vmsg->cm_fields['M'] = malloc(strlen(ser) + 1024); sprintf(vmsg->cm_fields['M'], - "Content-type: text/x-vcard" + "Content-type: " VCARD_MIME_TYPE "\r\n\r\n%s\r\n", ser); free(ser); } @@ -1189,19 +1329,9 @@ void vcard_fixed_output(char *ptr, int len) { } -char *serv_postfix_tcpdict(void) -{ - CtdlRegisterServiceHook(config.c_pftcpdict_port, /* Postfix */ - NULL, - check_get_greeting, - check_get, - NULL); - return "$Id$"; -} - -char *serv_vcard_init(void) +CTDL_MODULE_INIT(vcard) { struct ctdlroom qr; char filename[256]; @@ -1217,11 +1347,14 @@ char *serv_vcard_init(void) "Initialize Global Address Book"); CtdlRegisterProtoHook(cmd_qdir, "QDIR", "Query Directory"); CtdlRegisterProtoHook(cmd_gvsn, "GVSN", "Get Valid Screen Names"); + CtdlRegisterProtoHook(cmd_gvea, "GVEA", "Get Valid Email Addresses"); + CtdlRegisterProtoHook(cmd_dvca, "DVCA", "Dump VCard Addresses"); CtdlRegisterUserHook(vcard_newuser, EVT_NEWUSER); CtdlRegisterUserHook(vcard_purge, EVT_PURGEUSER); CtdlRegisterNetprocHook(vcard_extract_from_network); CtdlRegisterSessionHook(store_harvested_addresses, EVT_TIMER); CtdlRegisterFixedOutputHook("text/x-vcard", vcard_fixed_output); + CtdlRegisterFixedOutputHook("text/vcard", vcard_fixed_output); /* Create the Global ADdress Book room if necessary */ create_room(ADDRESS_BOOK_ROOM, 3, "", 0, 1, 0, VIEW_ADDRESSBOOK); @@ -1244,5 +1377,13 @@ char *serv_vcard_init(void) chown(filename, CTDLUID, (-1)); } + /* for postfix tcpdict */ + CtdlRegisterServiceHook(config.c_pftcpdict_port, /* Postfix */ + NULL, + check_get_greeting, + check_get, + NULL); + + /* return our Subversion id for the Log */ return "$Id$"; }