/* Re-insert of a card that has been removed by force removal */ VCardEmulError vcard_emul_force_card_insert(VReader *vreader) { VReaderEmul *vreader_emul; VCard *vcard; if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) { return VCARD_EMUL_FAIL; /* card is already removed */ } vreader_emul = vreader_get_private(vreader); /* if it's a softcard, get the saved vcard from the reader emul structure */ if (vreader_emul->saved_vcard) { vcard = vcard_reference(vreader_emul->saved_vcard); } else { /* it must be a physical card, rebuild it */ if (!PK11_IsPresent(vreader_emul->slot)) { /* physical card has been removed, not way to reinsert it */ return VCARD_EMUL_FAIL; } vcard = vcard_emul_mirror_card(vreader); } vreader_insert_card(vreader, vcard); vcard_free(vcard); return VCARD_EMUL_OK; }
void vevent_delete(VEvent *vevent) { if (vevent == NULL) { return; } vreader_free(vevent->reader); vcard_free(vevent->card); free(vevent); }
/* * This thread looks for card and reader insertions and puts events on the * event queue */ static void vcard_emul_event_thread(void *arg) { PK11SlotInfo *slot; VReader *vreader; VReaderEmul *vreader_emul; VCard *vcard; SECMODModule *module = (SECMODModule *)arg; do { slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500); if (slot == NULL) { break; } vreader = vcard_emul_find_vreader_from_slot(slot); if (vreader == NULL) { /* new vreader */ vreader_emul = vreader_emul_new(slot, default_card_type, default_type_params); vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); PK11_FreeSlot(slot); slot = NULL; vreader_add_reader(vreader); vreader_free(vreader); continue; } /* card remove/insert */ vreader_emul = vreader_get_private(vreader); if (PK11_IsPresent(slot)) { int series = PK11_GetSlotSeries(slot); if (series != vreader_emul->series) { if (vreader_emul->present) { vreader_insert_card(vreader, NULL); } vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_free(vcard); } vreader_emul->series = series; vreader_emul->present = 1; vreader_free(vreader); PK11_FreeSlot(slot); continue; } if (vreader_emul->present) { vreader_insert_card(vreader, NULL); } vreader_emul->series = 0; vreader_emul->present = 0; PK11_FreeSlot(slot); vreader_free(vreader); } while (1); }
/* Frees the BST */ void bst_free(bst *t) { if(t == NULL) //in event null tree passed return; if(t -> lsub != NULL) bst_free(t -> lsub); if(t -> rsub != NULL) bst_free(t -> rsub); vcard_free(t -> c); free(t); }
void bst_free(bst *t) { if (t == NULL) { return; } bst_free(t->lsub); bst_free(t->rsub); // once the leaves are reached, start freeing vcard_free(t->c); free(t); return; }
/* * TODODRW: change this into a CtdlModuleDo type function that returns alternative address info * for this local user. Something like CtdlModuleGoGetAddr(char *localuser, int type, char *alt_addr, size_t alt_addr_len) * where type can be ADDR_EMAIL, ADDR_FIDO, ADDR_UUCP, ADDR_WEB, ADDR_POSTAL etc etc. * This then begs the question of what should be returned. Is it wise to return a single char* using a comma as a * delimiter? Or would it be better to return a linked list of some kind? */ void local_to_inetemail(char *inetemail, char *localuser, size_t inetemail_len) { struct ctdluser us; struct vCard *v; strcpy(inetemail, ""); if (CtdlGetUser(&us, localuser) != 0) { return; } v = vcard_get_user(&us); if (v == NULL) { return; } extract_inet_email_addrs(inetemail, inetemail_len, NULL, 0, v, 1); vcard_free(v); }
/* * This is the main work of the emulator, handling the thread that looks for * changes in the readers and the cards. */ static void * passthru_emul_event_thread(void *args) { char *reader_list = NULL; int reader_list_len = 0; SCARD_READERSTATE_A *reader_states = NULL; int reader_count = 0; /* number of active readers */ int max_reader_count = 0; /* size of the reader_state array (including inactive readers) */ LONG rv; int timeout=1000; int i; do { /* variables to hold on to our new values until we are ready to replace * our old values */ char *new_reader_list = NULL; int new_reader_list_len = 0; int new_reader_count = 0; /* other temps */ char * reader_entry; VReader *reader; /* * First check to see if the reader list has changed */ rv = SCardListReaders(global_context, NULL, NULL, &new_reader_list_len); if (rv != SCARD_S_SUCCESS) { goto next; } /* * If the names have changed, we need to update our list and states. * This is where we detect reader insertions and removals. */ if (new_reader_list_len != reader_list_len) { /* update the list */ new_reader_list = (char *)malloc(new_reader_list_len); if (new_reader_list == NULL) { goto next; } rv = SCardListReaders(global_context, NULL, new_reader_list, &new_reader_list_len); if (rv != SCARD_S_SUCCESS) { free(new_reader_list); goto next; } /* clear out our event state */ for (i=0; i < reader_count; i++) { reader_states[i].dwEventState = 0; } /* count the readers and mark the ones that are still with us */ for (reader_entry = new_reader_list; *reader_entry; reader_entry += strlen(reader_entry)+1) { SCARD_READERSTATE_A *this_state; new_reader_count++; /* if the reader is still on the list, mark it present */ this_state = passthru_get_reader_state(reader_states, reader_count, reader_entry); if (this_state) { this_state->dwEventState = SCARD_STATE_PRESENT; } } /* eject any removed readers */ for (i=0; i < reader_count; i++) { if (reader_states[i].dwEventState == SCARD_STATE_PRESENT) { reader_states[i].dwEventState = 0; continue; } reader = vreader_get_reader_by_name(reader_states[i].szReader); vreader_remove_reader(reader); vreader_free(reader); reader_states[i].szReader = NULL; } /* handle the shrinking list */ if (new_reader_count < reader_count) { /* fold all the valid entries at the end of our reader_states * array up into those locations vacated by ejected readers. */ for (i=reader_count-1; i < (new_reader_count -1); i--) { if (reader_states[i].szReader) { SCARD_READERSTATE_A *blank_reader; blank_reader = passthru_get_blank_reader(reader_states, new_reader_count); assert(blank_reader); *blank_reader = reader_states[i]; reader_states[i].szReader = NULL; } } } /* handle the growing list */ if (new_reader_count > max_reader_count) { SCARD_READERSTATE_A *new_reader_states; /* grow the list */ new_reader_states = (SCARD_READERSTATE_A *)realloc(reader_states, sizeof(SCARD_READERSTATE_A)*new_reader_count); if (new_reader_states) { /* successful, update our current state */ reader_states = new_reader_states; max_reader_count = new_reader_count; } else { new_reader_count = max_reader_count; /* couldn't get enough * space to handle * all the new readers * */ } /* mark our new entries as empty */ for (i=reader_count; i > new_reader_count; i++) { reader_states[i].szReader = NULL; } } /* now walk the reader list, updating the state */ for (reader_entry = new_reader_list; *reader_entry; reader_entry += strlen(reader_entry)+1) { SCARD_READERSTATE_A *this_state; this_state = passthru_get_reader_state(reader_states, new_reader_count, reader_entry); if (this_state) { /* replace the old copy of the string with the new copy. * This will allow us to free reader_list at the end */ reader_states->szReader = reader_entry; continue; } /* this is a new reader, add it to the list */ this_state = passthru_get_blank_reader(reader_states, new_reader_count); if (!this_state) { continue; /* this can happen of we couldn't get enough slots in the grow list */ } this_state->szReader = reader_entry; this_state->dwCurrentState = SCARD_STATE_UNAWARE; reader = vreader_new(reader_entry, NULL, NULL); if (reader) { vreader_add_reader(reader); } vreader_free(reader); } /* finally update our current variables */ free(reader_list); reader_list = new_reader_list; reader_list_len = new_reader_list_len; reader_count = new_reader_count; } next: rv = SCardGetStatusChange(global_context, timeout, reader_states, reader_count); if (rv == SCARD_E_TIMEOUT) { continue; /* check for new readers */ } if (rv != SCARD_S_SUCCESS) { static int restarts = 0; VCardStatus status; /* try resetting the pcsc_lite subsystem */ SCardReleaseContext(global_context); global_context = 0; /* should close it */ printf("***** SCard failure %x\n", rv); restarts++; if (restarts >= 3) { printf("***** SCard failed %d times\n", restarts); return; /* exit thread */ } status = passthru_pcsc_lite_init(); assert(status == CARD_DONE); sleep(1); continue; } /* deal with card insertion/removal */ for (i=0; i < reader_count ; i++) { if ((reader_states[i].dwEventState & SCARD_STATE_CHANGED) == 0) { continue; } reader_states[i].dwCurrentState = reader_states[i].dwEventState; reader = vreader_get_reader_by_name(reader_states[i].szReader); if (reader == NULL) { continue; } if (reader_states[i].dwEventState & SCARD_STATE_EMPTY) { if (vreader_card_is_present(reader) == VREADER_OK) { vreader_insert_card(reader, NULL); } } if (reader_states[i].dwEventState & SCARD_STATE_PRESENT) { VCard *card; VCardStatus status = VCARD_FAIL; /* if there already was a card present, eject it before we * insert the new one */ if (vreader_card_is_present(reader) == VREADER_OK) { vreader_insert_card(reader, NULL); } card = vcard_new(NULL, NULL); if (card != NULL) { status = passthru_card_init(reader, card, "", NULL, NULL, NULL, 0); passthru_card_set_atr(card, reader_states[i].rgbAtr, reader_states[i].cbAtr); vcard_set_atr_func(card, passthru_card_get_atr); } if (status == VCARD_DONE) { vreader_insert_card(reader, card); } vcard_free(card); } vreader_free(reader); } } while (1); return NULL; }
VCardEmulError vcard_emul_init(const VCardEmulOptions *options) { SECStatus rv; PRBool ret, has_readers = PR_FALSE; VReader *vreader; VReaderEmul *vreader_emul; SECMODListLock *module_lock; SECMODModuleList *module_list; SECMODModuleList *mlp; int i; if (vcard_emul_init_called) { return VCARD_EMUL_INIT_ALREADY_INITED; } vcard_emul_init_called = 1; vreader_init(); vevent_queue_init(); if (options == NULL) { options = &default_options; } /* first initialize NSS */ if (options->nss_db) { rv = NSS_Init(options->nss_db); } else { gchar *path; #ifndef _WIN32 path = g_strdup("/etc/pki/nssdb"); #else if (g_get_system_config_dirs() == NULL || g_get_system_config_dirs()[0] == NULL) { return VCARD_EMUL_FAIL; } path = g_build_filename( g_get_system_config_dirs()[0], "pki", "nssdb", NULL); #endif rv = NSS_Init(path); g_free(path); } if (rv != SECSuccess) { return VCARD_EMUL_FAIL; } /* Set password callback function */ PK11_SetPasswordFunc(vcard_emul_get_password); /* set up soft cards emulated by software certs rather than physical cards * */ for (i = 0; i < options->vreader_count; i++) { int j; int cert_count; unsigned char **certs; int *cert_len; VCardKey **keys; PK11SlotInfo *slot; slot = PK11_FindSlotByName(options->vreader[i].name); if (slot == NULL) { continue; } vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, options->vreader[i].type_params); vreader = vreader_new(options->vreader[i].vname, vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); cert_count = options->vreader[i].cert_count; ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, options->vreader[i].cert_count); if (ret == PR_FALSE) { continue; } cert_count = 0; for (j = 0; j < options->vreader[i].cert_count; j++) { /* we should have a better way of identifying certs than by * nickname here */ CERTCertificate *cert = PK11_FindCertFromNickname( options->vreader[i].cert_name[j], NULL); if (cert == NULL) { continue; } certs[cert_count] = cert->derCert.data; cert_len[cert_count] = cert->derCert.len; keys[cert_count] = vcard_emul_make_key(slot, cert); /* this is safe because the key is still holding a cert reference */ CERT_DestroyCertificate(cert); cert_count++; } if (cert_count) { VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); /* allow insertion and removal of soft cards */ vreader_emul->saved_vcard = vcard_reference(vcard); vcard_free(vcard); vreader_free(vreader); has_readers = PR_TRUE; } g_free(certs); g_free(cert_len); g_free(keys); } /* if we aren't suppose to use hw, skip looking up hardware tokens */ if (!options->use_hw) { nss_emul_init = has_readers; return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; } /* make sure we have some PKCS #11 module loaded */ module_lock = SECMOD_GetDefaultModuleListLock(); module_list = SECMOD_GetDefaultModuleList(); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; if (module_has_removable_hw_slots(module)) { break; } } SECMOD_ReleaseReadLock(module_lock); /* now examine all the slots, finding which should be readers */ /* We should control this with options. For now we mirror out any * removable hardware slot */ default_card_type = options->hw_card_type; default_type_params = g_strdup(options->hw_type_params); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; /* Ignore the internal module */ if (module == NULL || module == SECMOD_GetInternalModule()) { continue; } for (i = 0; i < module->slotCount; i++) { PK11SlotInfo *slot = module->slots[i]; /* only map removable HW slots */ if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { continue; } if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) { /* * coolkey <= 1.1.0-20 emulates this reader if it can't find * any hardware readers. This causes problems, warn user of * problems. */ fprintf(stderr, "known bad coolkey version - see " "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n"); continue; } vreader_emul = vreader_emul_new(slot, options->hw_card_type, options->hw_type_params); vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); if (PK11_IsPresent(slot)) { VCard *vcard; vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); vcard_free(vcard); } } vcard_emul_new_event_thread(module); } SECMOD_ReleaseReadLock(module_lock); nss_emul_init = PR_TRUE; return VCARD_EMUL_OK; }
/* * This thread looks for card and reader insertions and puts events on the * event queue */ static void vcard_emul_event_thread(void *arg) { PK11SlotInfo *slot; VReader *vreader; VReaderEmul *vreader_emul; VCard *vcard; SECMODModule *module = (SECMODModule *)arg; do { /* * XXX - the latency value doesn't matter one bit. you only get no * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500), * hard coded in coolkey. And it isn't coolkey's fault - the timeout * value we pass get's dropped on the floor before C_WaitForSlotEvent * is called. */ slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500); if (slot == NULL) { /* this could be just a no event indication */ if (PORT_GetError() == SEC_ERROR_NO_EVENT) { continue; } break; } vreader = vcard_emul_find_vreader_from_slot(slot); if (vreader == NULL) { /* new vreader */ vreader_emul = vreader_emul_new(slot, default_card_type, default_type_params); vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); PK11_FreeSlot(slot); slot = NULL; vreader_add_reader(vreader); vreader_free(vreader); continue; } /* card remove/insert */ vreader_emul = vreader_get_private(vreader); if (PK11_IsPresent(slot)) { int series = PK11_GetSlotSeries(slot); if (series != vreader_emul->series) { if (vreader_emul->present) { vreader_insert_card(vreader, NULL); } vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_free(vcard); } vreader_emul->series = series; vreader_emul->present = 1; vreader_free(vreader); PK11_FreeSlot(slot); continue; } if (vreader_emul->present) { vreader_insert_card(vreader, NULL); } vreader_emul->series = 0; vreader_emul->present = 0; PK11_FreeSlot(slot); vreader_free(vreader); } while (1); }
VCardEmulError vcard_emul_init(const VCardEmulOptions *options) { SECStatus rv; PRBool ret, has_readers = PR_FALSE, need_coolkey_module; VReader *vreader; VReaderEmul *vreader_emul; SECMODListLock *module_lock; SECMODModuleList *module_list; SECMODModuleList *mlp; int i; if (vcard_emul_init_called) { return VCARD_EMUL_INIT_ALREADY_INITED; } vcard_emul_init_called = 1; vreader_init(); vevent_queue_init(); if (options == NULL) { options = &default_options; } /* first initialize NSS */ if (options->nss_db) { rv = NSS_Init(options->nss_db); } else { rv = NSS_Init("sql:/etc/pki/nssdb"); } if (rv != SECSuccess) { return VCARD_EMUL_FAIL; } /* Set password callback function */ PK11_SetPasswordFunc(vcard_emul_get_password); /* set up soft cards emulated by software certs rather than physical cards * */ for (i = 0; i < options->vreader_count; i++) { int j; int cert_count; unsigned char **certs; int *cert_len; VCardKey **keys; PK11SlotInfo *slot; slot = PK11_FindSlotByName(options->vreader[i].name); if (slot == NULL) { continue; } vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, options->vreader[i].type_params); vreader = vreader_new(options->vreader[i].vname, vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); cert_count = options->vreader[i].cert_count; ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, options->vreader[i].cert_count); if (ret == PR_FALSE) { continue; } cert_count = 0; for (j = 0; j < options->vreader[i].cert_count; j++) { /* we should have a better way of identifying certs than by * nickname here */ CERTCertificate *cert = PK11_FindCertFromNickname( options->vreader[i].cert_name[j], NULL); if (cert == NULL) { continue; } certs[cert_count] = cert->derCert.data; cert_len[cert_count] = cert->derCert.len; keys[cert_count] = vcard_emul_make_key(slot, cert); /* this is safe because the key is still holding a cert reference */ CERT_DestroyCertificate(cert); cert_count++; } if (cert_count) { VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); /* allow insertion and removal of soft cards */ vreader_emul->saved_vcard = vcard_reference(vcard); vcard_free(vcard); vreader_free(vreader); has_readers = PR_TRUE; } g_free(certs); g_free(cert_len); g_free(keys); } /* if we aren't suppose to use hw, skip looking up hardware tokens */ if (!options->use_hw) { nss_emul_init = has_readers; return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; } /* make sure we have some PKCS #11 module loaded */ module_lock = SECMOD_GetDefaultModuleListLock(); module_list = SECMOD_GetDefaultModuleList(); need_coolkey_module = !has_readers; SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; if (module_has_removable_hw_slots(module)) { need_coolkey_module = PR_FALSE; break; } } SECMOD_ReleaseReadLock(module_lock); if (need_coolkey_module) { SECMODModule *module; module = SECMOD_LoadUserModule( (char *)"library=libcoolkeypk11.so name=Coolkey", NULL, PR_FALSE); if (module == NULL) { return VCARD_EMUL_FAIL; } SECMOD_DestroyModule(module); /* free our reference, Module will still * be on the list. * until we destroy it */ } /* now examine all the slots, finding which should be readers */ /* We should control this with options. For now we mirror out any * removable hardware slot */ default_card_type = options->hw_card_type; default_type_params = strdup(options->hw_type_params); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; PRBool has_emul_slots = PR_FALSE; if (module == NULL) { continue; } for (i = 0; i < module->slotCount; i++) { PK11SlotInfo *slot = module->slots[i]; /* only map removable HW slots */ if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { continue; } vreader_emul = vreader_emul_new(slot, options->hw_card_type, options->hw_type_params); vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); has_readers = PR_TRUE; has_emul_slots = PR_TRUE; if (PK11_IsPresent(slot)) { VCard *vcard; vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); vcard_free(vcard); } } if (has_emul_slots) { vcard_emul_new_event_thread(module); } } SECMOD_ReleaseReadLock(module_lock); nss_emul_init = has_readers; return VCARD_EMUL_OK; }
/* * Attempt to read file, testing for valid vCard format. * Return: TRUE if file appears to be valid format. */ gint vcard_test_read_file( const gchar *fileSpec ) { gboolean haveStart; gchar *tagtemp = NULL, *tagname = NULL, *tagvalue = NULL, *tagtype = NULL, *line; VCardFile *cardFile; gint retVal, lines; if( ! fileSpec ) return MGU_NO_FILE; cardFile = vcard_create_path( fileSpec ); cardFile->retVal = MGU_SUCCESS; vcard_open_file( cardFile ); if( cardFile->retVal == MGU_SUCCESS ) { cardFile->retVal = MGU_BAD_FORMAT; haveStart = FALSE; lines = VCARD_TEST_LINES; while( lines > 0 ) { lines--; if( ( line = vcard_get_line( cardFile ) ) == NULL ) break; /* Parse line */ tagtemp = vcard_get_tagname( line, VCARD_SEP_TAG ); if( tagtemp == NULL ) { g_free( line ); continue; } tagvalue = vcard_get_tagvalue( line, VCARD_SEP_TAG ); if( tagvalue == NULL ) { g_free( tagtemp ); g_free( line ); continue; } tagname = vcard_get_tagname( tagtemp, VCARD_SEP_TYPE ); tagtype = vcard_get_tagvalue( tagtemp, VCARD_SEP_TYPE ); if( tagname == NULL ) { tagname = tagtemp; tagtemp = NULL; } if( g_strcasecmp( tagtype, VCARD_TYPE_QP ) == 0 ) { /* Quoted-Printable: could span multiple lines */ tagvalue = vcard_read_qp( cardFile, tagvalue ); vcard_unescape_qp( tagvalue ); } if( g_strcasecmp( tagname, VCARD_TAG_START ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { haveStart = TRUE; } if( g_strcasecmp( tagname, VCARD_TAG_END ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) { /* vCard is complete */ if( haveStart ) cardFile->retVal = MGU_SUCCESS; } g_free( tagname ); g_free( tagtype ); g_free( tagvalue ); g_free( tagtemp ); g_free( line ); } vcard_close_file( cardFile ); } retVal = cardFile->retVal; vcard_free( cardFile ); cardFile = NULL; return retVal; }
/* * Back end for cmd_auto() */ void hunt_for_autocomplete(long msgnum, char *search_string) { struct CtdlMessage *msg; struct vCard *v; char *value = NULL; char *value2 = NULL; int i = 0; char *nnn = NULL; msg = CtdlFetchMessage(msgnum, 1); if (msg == NULL) return; v = vcard_load(msg->cm_fields[eMesageText]); CM_Free(msg); /* * Try to match from a friendly name (the "fn" field). If there is * a match, return the entry in the form of: * Display Name <*****@*****.**> */ value = vcard_get_prop(v, "fn", 0, 0, 0); if (value != NULL) if (bmstrcasestr(value, search_string)) { value2 = vcard_get_prop(v, "email", 1, 0, 0); if (value2 == NULL) value2 = ""; cprintf("%s <%s>\n", value, value2); vcard_free(v); return; } /* * Try to match from a structured name (the "n" field). If there is * a match, return the entry in the form of: * Display Name <*****@*****.**> */ value = vcard_get_prop(v, "n", 0, 0, 0); if (value != NULL) if (bmstrcasestr(value, search_string)) { value2 = vcard_get_prop(v, "email", 1, 0, 0); if (value2 == NULL) value2 = ""; nnn = n_to_fn(value); cprintf("%s <%s>\n", nnn, value2); free(nnn); vcard_free(v); return; } /* * Try a partial match on all listed email addresses. */ i = 0; while (value = vcard_get_prop(v, "email", 1, i++, 0), value != NULL) { if (bmstrcasestr(value, search_string)) { if (vcard_get_prop(v, "fn", 0, 0, 0)) { cprintf("%s <%s>\n", vcard_get_prop(v, "fn", 0, 0, 0), value); } else if (vcard_get_prop(v, "n", 0, 0, 0)) { nnn = n_to_fn(vcard_get_prop(v, "n", 0, 0, 0)); cprintf("%s <%s>\n", nnn, value); free(nnn); } else { cprintf("%s\n", value); } vcard_free(v); return; } } vcard_free(v); }