/* ** Copyright 2000-2004 University of Illinois Board of Trustees ** Copyright 2000-2004 Mark D. Roth ** All rights reserved. ** ** fields.c - libphclient code to parse server field data ** ** Mark D. Roth */ #include #include #ifdef STDC_HEADERS # include # include #endif #include struct attriblist { char *name; unsigned long value; }; typedef struct attriblist attriblist_t; static attriblist_t attributes[] = { { "Always", PH_ATTRIB_ALWAYS }, { "Any", PH_ATTRIB_ANY }, { "Change", PH_ATTRIB_CHANGE }, { "Default", PH_ATTRIB_DEFAULT }, { "Encrypt", PH_ATTRIB_ENCRYPT }, { "ForcePub", PH_ATTRIB_FORCEPUB }, { "Indexed", PH_ATTRIB_INDEXED }, { "LocalPub", PH_ATTRIB_LOCALPUB }, { "Lookup", PH_ATTRIB_LOOKUP }, { "NoMeta", PH_ATTRIB_NOMETA }, { "NoPeople", PH_ATTRIB_NOPEOPLE }, { "Private", PH_ATTRIB_PRIVATE }, { "Public", PH_ATTRIB_PUBLIC }, { "Sacred", PH_ATTRIB_SACRED }, { "Turn", PH_ATTRIB_TURN }, { "Unique", PH_ATTRIB_UNIQUE }, { "PrivLookup", PH_ATTRIB_PRIVLOOKUP }, { "SacredPerson", PH_ATTRIB_SACREDPERSON }, { NULL, 0 } }; int ph_is_fieldinfo_cached(PH *ph) { return (ph->ph_fieldlist != NULL ? 1 : 0); } /* ph_free_fieldlist() - free a field list generated by ph_field_list(). */ static void ph_free_fieldlist(struct ph_fieldinfo *fi) { int i, j; #ifdef DEBUG printf("==> ph_free_fieldlist(fi=0x%lx)\n", fi); #endif for (i = 0; fi[i].pf_fnames != NULL; i++) { for (j = 0; fi[i].pf_fnames[j] != NULL; j++) free(fi[i].pf_fnames[j]); free(fi[i].pf_fnames); if (fi[i].pf_description != NULL) free(fi[i].pf_description); } free(fi); } /* maps an attribute string to the corresponding value */ static unsigned long ph_field_attrib_value(char *buf) { int i; for (i = 0; attributes[i].value != 0; i++) if (strcasecmp(buf, attributes[i].name) == 0) break; return attributes[i].value; } /* ** returns bitmask representation for a space-delimited string of ** multiple attributes */ static unsigned long ph_encode_field_attributes(char *buf) { char *attribp, *nextp; unsigned long bitmask = 0; for (nextp = buf; (attribp = strsep(&nextp, " ")) != NULL;) { if (*attribp == '\0') continue; BIT_SET(bitmask, ph_field_attrib_value(attribp)); } return bitmask; } #if 0 /* maps an attribute value to the corresponding string */ static char * ph_field_attrib_string(unsigned long attrib) { int i; for (i = 0; attributes[i].value != 0; i++) if (attributes[i].value == attrib) break; return attributes[i].name; } #endif /* ** writes a string of space-delimited attribute names corresponding to ** the numeric bitmask */ void ph_decode_field_attributes(unsigned long bitmask, char *buf, size_t bufsize) { int i; size_t buflen = 0; buf[0] = '\0'; for (i = 0; attributes[i].value != 0; i++) if (BIT_ISSET(bitmask, attributes[i].value)) buflen += snprintf(buf + buflen, bufsize - buflen, "%s ", attributes[i].name); } /* ** ph_retrieve_fieldinfo() - obtain a list of fields supported by the PH server. ** returns: ** 0 success ** -1 error (sets errno) */ int ph_retrieve_fieldinfo(PH *ph) { int numfields = 0, numaliases = 0; int i, code, id, save_errno; char *fieldnames, *value, *name; char buf[PH_BUF_SIZE]; void *ptr; ph_memblock_t *blockp; struct ph_fieldinfo *phfi; #ifdef DEBUG puts("==> ph_retrieve_fieldinfo()"); #endif /* don't load if already cached */ if (ph_is_fieldinfo_cached(ph)) return 0; /* tell the server to list field aliases, if supported */ ph_set_option(ph, "fieldaliases", NULL); if (ph_mmgr_malloc(ph->ph_mmgr, ph_MMGR_ARRAY, 0, sizeof(struct ph_fieldinfo), (ph_free_func_t)ph_free_fieldlist, &blockp) == -1) return -1; phfi = (struct ph_fieldinfo *)ph_mmgr_ptr(blockp); if (ph_send_command(ph, "fields") == -1) return -1; while ((i = ph_get_response(ph, &code, buf, sizeof(buf))) == 0) { #ifdef DEBUG printf("ph_retrieve_fieldinfo(): code=%d buf=\"%s\"\n", code, buf); #endif /* check the response code */ if (code < LR_OK && code > 0) continue; if (code == LR_OK) { ph->ph_fieldlist = phfi; ph_mmgr_free(blockp, 0); return 0; } if (code != -(LR_OK)) { ph_mmgr_free(blockp, 1); errno = EINVAL; return -1; } /* parse line from server */ if (ph_parse_response(buf, &id, &fieldnames, &value) == -1) { ph_mmgr_free(blockp, 1); errno = EINVAL; return -1; } #ifdef DEBUG printf("id=%d fieldnames=\"%s\" value=\"%s\"\n", id, fieldnames, value); #endif /* allocate memory if it's a new entry */ if (numfields == 0 || id != phfi[numfields - 1].pf_id) { #ifdef DEBUG printf("allocating memory - numfields = %d\n", numfields); #endif if (ph_mmgr_array_add(blockp, numfields + 2) == -1) { save_errno = errno; ph_mmgr_free(blockp, 1); errno = save_errno; return -1; } phfi = (struct ph_fieldinfo *)ph_mmgr_ptr(blockp); /* set field id */ phfi[numfields].pf_id = id; /* set field names */ numaliases = 0; while ((name = strsep(&fieldnames, " ,")) != NULL) { ptr = realloc(phfi[numfields].pf_fnames, (numaliases + 2) * sizeof(char *)); if (ptr == NULL) { save_errno = errno; ph_mmgr_free(blockp, 1); errno = save_errno; return -1; } phfi[numfields].pf_fnames = (char **)ptr; phfi[numfields].pf_fnames[numaliases] = strdup(name); phfi[numfields].pf_fnames[++numaliases] = NULL; } if (phfi[numfields].pf_fnames[0] == NULL) { save_errno = errno; ph_mmgr_free(blockp, 1); errno = save_errno; return -1; } /* set max_size */ i = sscanf(value, "max %d", &(phfi[numfields].pf_max_size)); if (i != 1) { ph_mmgr_free(blockp, 1); errno = EINVAL; return -1; } #ifdef DEBUG printf("max_size = %d\n", phfi[numfields].pf_max_size); #endif /* extract the field attributes */ #ifdef DEBUG printf("attributes = \"%s\"\n", value + 4); #endif phfi[numfields].pf_attrib = ph_encode_field_attributes(strchr(value + 4, ' ')); numfields++; } else /* second line for this field */ { /* otherwise, extract the description */ #ifdef DEBUG printf("description = \"%s\"\n", value); #endif phfi[numfields - 1].pf_description = strdup(value); if (phfi[numfields - 1].pf_description == NULL) { save_errno = errno; ph_mmgr_free(blockp, 1); errno = save_errno; return -1; } } /* end of loop - call ph_get_response() again */ } /* in case ph_get_response() returned an error */ save_errno = errno; ph_mmgr_free(blockp, 1); errno = save_errno; return -1; } /* ** ph_get_fieldinfo() - return the description for a given field. ** returns: ** 0 success ** -1 error (sets errno) ** PH_ERR_DATAERR unknown field */ int ph_get_fieldinfo(PH *ph, char *fieldname, struct ph_fieldinfo **fieldinfo) { int i, j; if (!ph_is_fieldinfo_cached(ph) && ph_retrieve_fieldinfo(ph) == -1) return -1; for (i = 0; ph->ph_fieldlist[i].pf_fnames != NULL; i++) for (j = 0; ph->ph_fieldlist[i].pf_fnames[j] != NULL; j++) if (strcasecmp(ph->ph_fieldlist[i].pf_fnames[j], fieldname) == 0) { *fieldinfo = &(ph->ph_fieldlist[i]); return 0; } return PH_ERR_DATAERR; } /* ** ph_fieldinfo_iterate() - return the next field info structure. ** returns: ** 1 data returned ** 0 no more data ** -1 error (sets errno) */ int ph_fieldinfo_iterate(PH *ph, struct ph_fieldinfo **fieldinfo) { if (!ph_is_fieldinfo_cached(ph) && ph_retrieve_fieldinfo(ph) == -1) return -1; /* first entry */ if (*fieldinfo == NULL) { *fieldinfo = &(ph->ph_fieldlist[0]); return 1; } /* next element */ (*fieldinfo)++; if ((*fieldinfo)->pf_fnames != NULL) return 1; /* end of list */ *fieldinfo = NULL; return 0; } /* ** ph_free_fieldinfo() - free fieldlist associated with ph. */ void ph_free_fieldinfo(PH *ph) { if (ph->ph_fieldlist != NULL) ph_free_fieldlist(ph->ph_fieldlist); ph->ph_fieldlist = NULL; }