/* * FISG - User- and nick-related datastructure handling * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2003-2004 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ #include #include #include #include #include "fisg.h" #include "th_util.h" #include "th_string.h" /* * Userlist handling */ /* Allocate new t_user_data structure */ t_user_data *user_data_new(void) { t_user_data *pData; /* Allocate the structure */ pData = (t_user_data *) calloc(1, sizeof(t_user_data)); if (!pData) return NULL; return pData; } /* Free t_user_data structure */ void user_data_free(t_user_data *pData) { t_user_entry *pCurr, *pNext; if (pData) { /* Free linked list */ pCurr = pData->pList; while (pCurr) { pNext = pCurr->pNext; user_free(pCurr); pCurr = pNext; } /* Free index */ free(pData->ppIndex); /* Clear structure */ pData->pList = NULL; pData->ppIndex = NULL; pData->dirtyN = pData->dirtyIndex = FALSE; /* Free structure */ free(pData); } } /* Allocate a new user node */ t_user_entry *user_new(char *userHandle) { t_user_entry *pResult; /* Allocate memory for new node */ pResult = (t_user_entry *) calloc(1, sizeof(t_user_entry)); if (!pResult) return NULL; /* Set fields */ th_strcpy(&pResult->userHandle, userHandle); return pResult; } /* Free user node and data */ void user_free(t_user_entry *pUser) { assert(pUser); if (pUser->userHandle) free(pUser->userHandle); if (pUser->picPath) free(pUser->picPath); if (pUser->linkURL) free(pUser->linkURL); if (pUser->sComment) free(pUser->sComment); free(pUser); } /* Insert given node to linked list */ void user_insert(t_user_data *pData, t_user_entry *pNode) { assert(pData); assert(pNode); /* Make dirty */ pData->dirtyN = pData->dirtyIndex = TRUE; /* Insert node */ if (pData->pList) { /* The first node's pPrev points to last node */ LPREV = pData->pList->pPrev; /* New node's prev = Previous last node */ pData->pList->pPrev->pNext = pNode; /* Previous last node's next = New node */ pData->pList->pPrev = pNode; /* New last node = New node */ LNEXT = NULL; /* But next is NULL! */ } else { pData->pList = pNode; /* First node ... */ LPREV = pNode; /* ... it's also last */ LNEXT = NULL; /* But next is NULL! */ } } /* Delete given user node from linked list */ void user_delete(t_user_data *pData, t_user_entry *pNode) { assert(pData); assert(pData->pList); assert(pNode); /* Make dirty */ pData->dirtyN = pData->dirtyIndex = TRUE; /* Delete node */ if (LPREV) LPREV->pNext = LNEXT; if (LNEXT) LNEXT->pPrev = LPREV; else pData->pList->pPrev = LPREV; LPREV = LNEXT = NULL; } /* * User data structures handling */ /* Compare function for qsort() that compares 2 nodes for fTotalScore */ int user_data_index_cmp(const void *pNode1, const void *pNode2) { t_user_entry *pUser1, *pUser2; pUser1 = * (t_user_entry **) pNode1; pUser2 = * (t_user_entry **) pNode2; if (pUser1->fTotalScore > pUser2->fTotalScore) return -1; else if (pUser1->fTotalScore < pUser2->fTotalScore) return 1; else return 0; } /* Create a user index for given t_user_data structure * from nodes in the linked list. */ int user_data_makeindex(t_user_data *pData) { t_user_entry *pCurr; t_ulint i; assert(pData); /* Free old index, if it exists */ free(pData->ppIndex); pData->ppIndex = NULL; /* Computer number of nodes */ for (pData->n = 0, pCurr = pData->pList; pCurr; pCurr = pCurr->pNext) pData->n++; pData->dirtyN = FALSE; /* Check number of nodes */ if (pData->n == 0) return 0; /* Allocate memory for index */ pData->ppIndex = (t_user_entry **) malloc(sizeof(t_user_entry *) * pData->n); if (pData->ppIndex == NULL) return -1; /* Copy node-pointers to the index-table */ i = 0; pCurr = pData->pList; while (pCurr && (i < pData->n)) { pData->ppIndex[i++] = pCurr; pCurr = pCurr->pNext; } if (i != pData->n) return -2; pData->dirtyIndex = FALSE; return 0; } /* * Nicklist/hash handling */ /* Insert given node into the nicklist/hashtable */ int nickhash_insert(t_str_hash nickList, t_str_node *pNode) { int i; char *tmpNick; assert(nickList); assert(pNode); assert(pNode->pcStr); /* Find first non-token character from nick */ tmpNick = pNode->pcStr; while ((*tmpNick == '*') || (*tmpNick == '?')) tmpNick++; i = th_tolower(*tmpNick); /* Check the hash index */ if ((i < 0) && (i >= SET_HASH_MAXINDEX)) return -1; /* Insert node in the linked list */ if (nickList[i]) { /* The first node's pPrev points to last node */ pNode->pPrev = nickList[i]->pPrev; /* New node's prev = Previous last node */ nickList[i]->pPrev->pNext = pNode; /* Previous last node's next = New node */ nickList[i]->pPrev = pNode; /* New last node = New node */ pNode->pNext = NULL; /* But next is NULL! */ } else { nickList[i] = pNode; /* First node */ pNode->pPrev = pNode; /* But also last */ pNode->pNext = NULL; /* But next is NULL! */ } return 0; } /* Check if given nick is in the nicklist */ t_str_node *nickhash_search(t_str_hash nickList, char *findNick) { t_str_node *pCurr; int i, j; BOOL isFound; assert(nickList); isFound = FALSE; pCurr = NULL; j = 0; /* Check hash */ while ((!isFound) && (findNick[j])) { i = th_tolower(findNick[j]); if ((i >= 0) && (i < SET_HASH_MAXINDEX)) { /* Find from linked list */ pCurr = nickList[i]; while (pCurr && (!isFound)) { if (th_strcasematch(findNick, pCurr->pcStr)) isFound = TRUE; else pCurr = pCurr->pNext; } } j++; } /* Return result */ if (isFound) return pCurr; else return NULL; } /* * Userfile parser */ /* Get a field ending to line-end or colon ':' */ void parse_pfield1(char *inLine, char *tmpBuf, size_t bufSize, size_t *linePos) { size_t i = 0; while (inLine[*linePos] && (inLine[*linePos] != ':') && (i < bufSize)) tmpBuf[i++] = inLine[(*linePos)++]; tmpBuf[i++] = 0; } /* Get a field ending to line-end, whitespace or colon ':' */ void parse_pfield2(char *inLine, char *tmpBuf, size_t bufSize, size_t *linePos) { size_t i = 0; while (inLine[*linePos] && !th_isspace(inLine[*linePos]) && (inLine[*linePos] != ':') && (i < bufSize)) tmpBuf[i++] = inLine[(*linePos)++]; tmpBuf[i++] = 0; } /* Get a field ending to line-end or whitespace */ void parse_pfield3(char *inLine, char *tmpBuf, size_t bufSize, size_t *linePos) { size_t i = 0; while (inLine[*linePos] && !th_isspace(inLine[*linePos]) && (i < bufSize)) tmpBuf[i++] = inLine[(*linePos)++]; tmpBuf[i++] = 0; } /* Parse a given userfile to nick and user information */ int parse_userfile(char *userFilename, t_stats *pStats, t_fisgconfig *pCfg) { char inLine[SET_MAX_BUF + 1], tmpStr[SET_MAX_BUF + 1]; FILE *inFile; size_t lineNum, linePos; t_user_entry *tmpUser = NULL; t_str_node *tmpNick = NULL; BOOL isIgnored; assert(pStats); /* Get configuration options */ /* Try to open the file */ if ((inFile = fopen(userFilename, "ra")) == NULL) return -1; /* Read and parse the data */ lineNum = 0; while (fgets(inLine, SET_MAX_BUF, inFile) != NULL) { linePos = 0; while (inLine[linePos] && !th_iscrlf(inLine[linePos])) linePos++; inLine[linePos] = 0; lineNum++; linePos = 0; /* Check if the line is OK and what type it is */ if (inLine[0] && (inLine[linePos] != '#')) { /* Check if it's ignored user */ if (inLine[linePos] == '!') { linePos++; isIgnored = TRUE; } else isIgnored = FALSE; /* Get the user handle */ parse_pfield1(inLine, tmpStr, SET_MAX_BUF, &linePos); /* Check if next field exists */ if (inLine[linePos] != ':') { THERR("Error in userfile '%s', line %i - missing fields.\n", userFilename, lineNum); } else { /* Allocate a new user and nick records */ tmpUser = user_new(tmpStr); tmpUser->isIgnored = isIgnored; tmpUser->isManaged = TRUE; user_insert(pStats->usersList, tmpUser); /* Get alias nicks */ linePos++; while (inLine[linePos] && (inLine[linePos] != ':')) { /* Get one nick */ th_findnext(inLine, &linePos); parse_pfield2(inLine, tmpStr, SET_MAX_BUF, &linePos); th_findnext(inLine, &linePos); /* Add to user */ tmpNick = th_strnode_new(tmpStr, 0, tmpUser); if (nickhash_insert(pStats->nickList, tmpNick) != 0) THERR("nickhash_insert() failed, hash: '%s'\n", tmpStr); } /* Check if image path is given */ if (inLine[linePos] == ':') { /* Get image path */ linePos++; if (inLine[linePos] != ':') { parse_pfield1(inLine, tmpStr, SET_MAX_BUF, &linePos); if (tmpStr[0]) th_strcpy(&tmpUser->picPath, tmpStr); } if (inLine[linePos] == ':') { /* Get user URL */ linePos++; th_findnext(inLine, &linePos); parse_pfield3(inLine, tmpStr, SET_MAX_BUF, &linePos); if (tmpStr[0]) th_strcpy(&tmpUser->linkURL, tmpStr); } } } } } /* if (fgets()) */ return 0; }