/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // System includes #include #include #include #include #include // Miranda Includes #include #include #include // Fortune include #include "fortune.h" #include "m_fortunemsg.h" void bigEndian2littleEndian(void *, size_t); unsigned int random(unsigned int); size_t readFortuneItem(char *, unsigned int, FILE *, FILE *, unsigned char, unsigned int); void normalizeMsg(char *); void trimFortune(char *); void addCRBeforeLF(char *, unsigned int); #define isSpace(a) (a == ' ' || a == '\t' || a == '\r' || a == '\n') BOOL readFortune(const char *dbSetting, char *messageBuf, unsigned int maxFortuneMsg) { DBVARIANT dbv; char datFilename[MAX_PATH+1], fortuneFilename[MAX_PATH+1]; FILE *fDatfile, *fFortunefile; DATFILEHEADER datHeader; int rCountdown; if (DBGetContactSetting(NULL, MODULE_NAME, dbSetting, &dbv)) return FALSE; makeAbsolute(datFilename, dbv.pszVal); DBFreeVariant(&dbv); if (strlen(datFilename) < 5) return FALSE; if (!(fDatfile=fopen(datFilename, "rb"))) return FALSE; if (fread(&datHeader, sizeof(DATFILEHEADER), 1, fDatfile) < 1) return FALSE; bigEndian2littleEndian(&(datHeader.dat_version), sizeof(unsigned int)); bigEndian2littleEndian(&(datHeader.dat_numstr), sizeof(unsigned int)); bigEndian2littleEndian(&(datHeader.dat_longlen), sizeof(unsigned int)); bigEndian2littleEndian(&(datHeader.dat_shortlen), sizeof(unsigned int)); bigEndian2littleEndian(&(datHeader.dat_flags), sizeof(unsigned int)); if (datHeader.dat_shortlen > maxFortuneMsg) return FALSE; strcpy(fortuneFilename, datFilename); fortuneFilename[strlen(fortuneFilename) - 4] = '\0'; if (!(fFortunefile=fopen(fortuneFilename, "rt"))) return FALSE; for(rCountdown=MAX_RETRIES; rCountdown && readFortuneItem(messageBuf, random(datHeader.dat_numstr), fDatfile, fFortunefile, datHeader.DELIM, maxFortuneMsg) == -1; rCountdown--); fclose(fDatfile); fclose(fFortunefile); return !!rCountdown; } void bigEndian2littleEndian(void *convField, size_t fieldSize) { size_t i; char aux[128]; memcpy(aux, convField, fieldSize); for (i=0; i < (fieldSize / 2); i++) { char aux2; int j = fieldSize - i - 1; aux2 = aux[i]; aux[i] = aux[j]; aux[j] = aux2; } memcpy(convField, aux, fieldSize); } unsigned int random(unsigned int maxNumber) { static time_t seed = 0; if (seed == 0) { (void)time(&seed); srand((unsigned int)seed); } return (unsigned int)(rand() % maxNumber); } size_t readFortuneItem(char *fortuneMsg, unsigned int nroItem, FILE *fDatfile, FILE *fFortunefile, unsigned char delimiter, unsigned int maxFortuneMsg) { size_t countBytes = 0; f_offset fortuneOffset; char buffer[2*FORTUNE_BUFSIZE], messageBuf[2*FORTUNE_BUFSIZE]; messageBuf[0] = fortuneMsg[0] = '\0'; if (fseek(fDatfile, (long)(sizeof(DATFILEHEADER) + nroItem * sizeof(f_offset)), SEEK_SET)) return 0; if (fread(&fortuneOffset, sizeof(f_offset), 1, fDatfile) < 1) return 0; bigEndian2littleEndian(&fortuneOffset, sizeof(f_offset)); if (fseek(fFortunefile, (long)fortuneOffset, SEEK_SET)) return 0; while(fgets(buffer, 2*FORTUNE_BUFSIZE, fFortunefile) != NULL && !(buffer[0] == delimiter && buffer[1] == '\n')) { if ((countBytes += strlen(buffer)) > (2*FORTUNE_BUFSIZE-1)) return -1; strcat(messageBuf, buffer); } if (DBGetContactSettingByte(NULL, MODULE_NAME, "OneLine", 0)) normalizeMsg(messageBuf); else { trimFortune(messageBuf); if (!DBGetContactSettingByte(NULL, MODULE_NAME, "RemoveCR", 0)) addCRBeforeLF(messageBuf, maxFortuneMsg); } if ((countBytes = strlen(messageBuf)) > maxFortuneMsg) return -1; strcpy(fortuneMsg, messageBuf); return countBytes; } void normalizeMsg(char *fortuneMsg) { char buffer[2*FORTUNE_BUFSIZE], *str; strcpy(buffer, fortuneMsg); if (!(str=strtok(buffer, " \t\r\n"))) fortuneMsg[0] = '\0'; else { strcpy(fortuneMsg, str); while(str = strtok(NULL, " \t\r\n")) { strcat(fortuneMsg, " "); strcat(fortuneMsg, str); } } } void trimFortune(char *fortuneMsg) { int i; for (i=strlen(fortuneMsg)-1; i >= 0 && isSpace(fortuneMsg[i]); i--) fortuneMsg[i] = '\0'; } void addCRBeforeLF(char *fortuneMsg, unsigned int maxFortuneMsg) { int i, j, empty; char buffer[2*FORTUNE_BUFSIZE]; if ((empty = maxFortuneMsg - strlen(fortuneMsg)) < 0) return; strcpy(buffer, fortuneMsg); for (i=j=0; buffer[i]; i++) { if (empty && buffer[i] == '\n') { empty--; fortuneMsg[j++] = '\r'; } fortuneMsg[j++] = buffer[i]; } fortuneMsg[j] = '\0'; } BOOL selectRandomFile(char *datFilename) { DBVARIANT dbv; char szDir[MAX_PATH+1], szMask[MAX_PATH+1]; WIN32_FIND_DATA FileData; HANDLE hSearch; int count = 0; datFilename[0] = '\0'; if (DBGetContactSetting(NULL, MODULE_NAME, "FortuneDir", &dbv)) return FALSE; strcpy(szDir, dbv.pszVal); DBFreeVariant(&dbv); makeAbsolute(szMask, szDir); strcat(szMask, "\\*.dat"); if ((hSearch=FindFirstFile(szMask, &FileData)) == INVALID_HANDLE_VALUE) return FALSE; do { count++; } while (FindNextFile(hSearch, &FileData)); count = random(count); if ((hSearch=FindFirstFile(szMask, &FileData)) == INVALID_HANDLE_VALUE) return FALSE; do { if(count-- == 0) { strcpy(datFilename, szDir); strcat(datFilename, "\\"); strcat(datFilename, FileData.cFileName); return TRUE; } } while (FindNextFile(hSearch, &FileData)); return FALSE; } char *makeRelative(char *returnPath, const char *path) { strcpy(returnPath, path); if (ServiceExists(MS_UTILS_PATHTORELATIVE)) CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)path, (LPARAM)returnPath); return returnPath; } char *makeAbsolute(char *returnPath, const char *path) { strcpy(returnPath, path); if (ServiceExists(MS_UTILS_PATHTOABSOLUTE)) CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)path, (LPARAM)returnPath); return returnPath; }