#include "stdafx.h" int readFileIntoArray(int fileNumber, char *FileContents[]) { char dbSetting[20], temp[MAX_STRING_LENGTH]; mir_snprintf(dbSetting, "fn%d", fileNumber); char *szVar = db_get_sa(0, MODNAME, dbSetting); if (szVar == nullptr) return 0; char tszFileName[MAX_PATH]; if (!strncmp("http://", szVar, 7) || !strncmp("https://", szVar, 7)) mir_snprintf(tszFileName, "%s\\plugins\\fn%d.html", getMimDir(temp), fileNumber); else mir_strncpy(tszFileName, szVar, _countof(tszFileName)); mir_free(szVar); FILE* file = fopen(tszFileName, "r"); if (file == nullptr) return 0; // read the file into the FileContents array // free this array before stringReplacer() returns int i; for (i = 0; fgets(temp, MAX_STRING_LENGTH - 1, file); i++) { if (temp[mir_strlen(temp) - 1] == '\n') temp[mir_strlen(temp) - 1] = '\0'; else temp[mir_strlen(temp)] = '\0'; FileContents[i] = (char*)malloc(mir_strlen(temp) + 1); if (FileContents[i] == nullptr) break; mir_strcpy(FileContents[i], temp); } fclose(file); return i; } int getNumber(const char* line) { int i; return sscanf(line, "%d", &i) == 1 ? i : -1; } int findWordInString(const char* line, const char* string, int* lengthOfWord, int flag) /* flag = 0 %from, flag = 1 %until */ { unsigned int i, j = 0; char word[64] = "", OpenDivider[8], CloseDivider[8]; strncpy(OpenDivider, "(\"", sizeof(OpenDivider)); strncpy(CloseDivider, "\")", sizeof(CloseDivider)); /* get the word we r looking for */ if (!strncmp(string, OpenDivider, mir_strlen(OpenDivider))) { for (i = 2; strncmp(&string[i], CloseDivider, mir_strlen(CloseDivider)); i++) { word[j] = string[i]; word[++j] = '\0'; } } i = 0; *lengthOfWord = (int)(mir_strlen(word) + mir_strlen(CloseDivider) + mir_strlen(OpenDivider)); /* find the word in the line */ while (i < (mir_strlen(line) - mir_strlen(word))) { if (!strncmp(&line[i], word, mir_strlen(word))) { if (!flag) return i + (int)mir_strlen(word); /* the next char after the word */ else return i; /* the char before the word */ } i++; } return -1; } int findLine(char* FileContents[], const char* string, int linesInFile, int startLine, int *positionInOldString) { char tmp[5]; int i = getNumber(&string[*positionInOldString]); // check if blank if (string[*positionInOldString] == ')') return startLine; // check if its a number if (i != -1) { *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10)) - 1; return i; } // lastline if (!strncmp(&string[*positionInOldString], "lastline(", mir_strlen("lastline("))) { *positionInOldString += (int)mir_strlen("lastline("); i = getNumber(&string[*positionInOldString]); if (i != -1) { *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10)); return linesInFile - (i + 1); } (*positionInOldString)++; return (linesInFile - 1); } // string if (string[*positionInOldString] == '\"') { char string2Find[256]; int j = 0; // get the word to find for (i = (*positionInOldString + 1); strncmp(&string[i], "\")", 2); i++) { string2Find[j] = string[i]; string2Find[++j] = '\0'; } // find the word for (j = startLine; j < linesInFile; j++) { if (strstr(FileContents[j], string2Find)) { i = j; break; } i = -1; } *positionInOldString += (int)(mir_strlen(string2Find) + mir_strlen("\"\")")); if (i == -1) return i; // allow for a +- after the word to go up or down lines if (string[*positionInOldString] == '+') { *positionInOldString += 1; j = getNumber(&string[*positionInOldString]); if (j != -1) { *positionInOldString += (int)mir_strlen(_itoa(j, tmp, 10)) - 2; return i + j; } } else if (string[*positionInOldString] == '-') { *positionInOldString += 1; j = getNumber(&string[*positionInOldString]); if (j != -1) { *positionInOldString += (int)mir_strlen(_itoa(j, tmp, 10)) - 2; return i - j; } } else { *positionInOldString -= 2; return i; } } return -1; } int findChar(char* FileContents[], const char* string, int startLine, int *positionInOldString, int startChar, int startEnd) // 0=start, 1=end for startEnd { char tmp[5]; int i = getNumber(&string[*positionInOldString]); // check if its a number if (i != -1) { *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10)) - 1; return i; } // string if (string[*positionInOldString] == '\"') { char string2Find[256]; unsigned int j = 0; // get the word to find for (i = (*positionInOldString + 1); strncmp(&string[i], "\")", 2); i++) { string2Find[j] = string[i]; string2Find[++j] = '\0'; } // find the word for (j = 0; j < mir_strlen(FileContents[startLine]); j++) if (!strncmp(&FileContents[startLine][j], string2Find, mir_strlen(string2Find))) break; if (j == mir_strlen(FileContents[startLine])) return -1; *positionInOldString += (int)mir_strlen(string2Find) + 1; return (startEnd) ? j : j + (int)mir_strlen(string2Find); } // csv( if (!strncmp(&string[*positionInOldString], "csv(", mir_strlen("csv("))) { char seperator; int j = 0, k = startChar; *positionInOldString += (int)mir_strlen("csv("); if (!strncmp(&string[*positionInOldString], "tab", 3)) { *positionInOldString += 3; seperator = '\t'; } else if (!strncmp(&string[*positionInOldString], "space", 5)) { *positionInOldString += 5; seperator = ' '; } else { seperator = string[*positionInOldString]; *positionInOldString += 1; } i = getNumber(&string[*positionInOldString]); if (i == -1) return -1; *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10)); while (j < i) { if (FileContents[startLine][k] == '\0') break; if (FileContents[startLine][k] == seperator) j++; k++; } return k; } return -1; } // do the compare("A","B","X","Y") void checkStringForcompare(CMStringA &str) { if (!strstr(str, "compare(\"")) return; char *A, *B, *X, *Y, *copyOfStr = NEWSTR_ALLOCA(str.c_str()); CMStringA tmp; unsigned int i, j = 0, s = str.GetLength(); for (i = 0; i < s; i++) { if (!strncmp(str.c_str()+i, "compare(\"", mir_strlen("compare(\""))) { i += (int)mir_strlen("compare(\""); A = strtok(©OfStr[i], "\",\""); B = strtok(nullptr, "\",\""); X = strtok(nullptr, "\",\""); Y = strtok(nullptr, ",\")"); j = Y - ©OfStr[i] + (int)mir_strlen(Y) + 1; if (A && B && X && Y) { if (!mir_strcmp(A, B)) tmp.Append(X); else tmp.Append(Y); } else tmp.Append(str.c_str()+i, j); i += j; } else tmp.AppendChar(copyOfStr[i]); } str = tmp; } // do save("A","B") A is DBVar name, B is value void checkStringForSave(MCONTACT hContact, CMStringA &str) { if (!strstr(str, "save(\"")) return; char *A, *B, *copyOfStr = NEWSTR_ALLOCA(str.c_str()); unsigned int i, j = 0, s = str.GetLength(); CMStringA tmp; for (i = 0; i < s; i++) { if (!strncmp(str.c_str()+i, "save(\"", mir_strlen("save(\""))) { i += (int)mir_strlen("save(\""); A = strtok(©OfStr[i], "\",\""); B = strtok(nullptr, ",\")"); j = B - ©OfStr[i] + (int)mir_strlen(B) + 1; if (A && B) g_plugin.setString(hContact, A, B); else tmp.Append(str.c_str()+i, j); i += j; } else tmp.AppendChar(copyOfStr[i]); } str = tmp; } // do load("A") A is DBVar name void checkStringForLoad(MCONTACT hContact, CMStringA &str) { if (!strstr(str, "load(\"")) return; char *A, *copyOfStr = NEWSTR_ALLOCA(str.c_str()); unsigned int i, j = 0, s = str.GetLength(); CMStringA tmp; for (i = 0; i < s; i++) { if (!strncmp(str.c_str()+i, "load(\"", mir_strlen("load(\""))) { i += (int)mir_strlen("load(\""); A = strtok(©OfStr[i], "\")"); j = A - ©OfStr[i] + (int)mir_strlen(A) + 1; if (A) { DBVARIANT dbv; if (!db_get_s(hContact, MODNAME, A, &dbv)) { tmp.Append(dbv.pszVal); db_free(&dbv); } } else tmp.Append(str.c_str()+i, j); i += j; } else tmp.AppendChar(copyOfStr[i]); } str = tmp; } // do saveN("A","B","C","D") A is module, B is setting, c is value, D is type 0/b 1/w 2/d 3/s void checkStringForSaveN(CMStringA &str) { if (!strstr(str, "saveN(\"")) return; char *A, *B, *C, *D, *copyOfStr = NEWSTR_ALLOCA(str.c_str()); unsigned int i, j = 0, s = str.GetLength(); CMStringA tmp; for (i = 0; i < s; i++) { if (!strncmp(str.c_str()+i, "saveN(\"", mir_strlen("saveN(\""))) { i += (int)mir_strlen("saveN(\""); A = strtok(©OfStr[i], "\",\""); B = strtok(nullptr, ",\""); C = strtok(nullptr, ",\""); D = strtok(nullptr, ",\")"); j = D - ©OfStr[i] + (int)mir_strlen(D) + 1; if (A && B && C && D) { switch (D[0]) { case '0': case 'b': db_set_b(0, A, B, (uint8_t)atoi(C)); break; case '1': case 'w': db_set_w(0, A, B, (uint16_t)atoi(C)); break; case '2': case 'd': db_set_dw(0, A, B, (uint32_t)atoi(C)); break; case '3': case 's': db_set_s(0, A, B, C); break; } } else tmp.Append(str.c_str()+i, j); i += j; } else tmp.AppendChar(copyOfStr[i]); } str = tmp; } // do loadN("A","B") A is module, B is setting void checkStringForLoadN(CMStringA &str) { if (!strstr(str, "loadN(\"")) return; char *copyOfStr = NEWSTR_ALLOCA(str.c_str()), temp[32]; unsigned int i, j = 0, s = str.GetLength(); CMStringA tmp; for (i = 0; i < s; i++) { if (!strncmp(str.c_str()+i, "loadN(\"", mir_strlen("loadN(\""))) { i += (int)mir_strlen("loadN(\""); char *A = strtok(©OfStr[i], "\",\""); char *B = strtok(nullptr, ",\")"); if (A && B) { j = B - ©OfStr[i] + (int)mir_strlen(B) + 1; DBVARIANT dbv; if (!db_get(NULL, A, B, &dbv)) { switch (dbv.type) { case DBVT_BYTE: tmp.Append(_itoa(dbv.bVal, temp, 10)); break; case DBVT_WORD: tmp.Append(_itoa(dbv.wVal, temp, 10)); break; case DBVT_DWORD: tmp.Append(_itoa(dbv.dVal, temp, 10)); break; case DBVT_ASCIIZ: tmp.Append(dbv.pszVal); break; } db_free(&dbv); } } else tmp.Append(str.c_str()+i, i); i += j; } else tmp.AppendChar(copyOfStr[i]); } str = tmp; } BOOL GetLastWriteTime(HANDLE hFile, LPSTR lpszString) { FILETIME ftCreate, ftAccess, ftWrite; SYSTEMTIME stUTC, stLocal; // Retrieve the file times for the file. if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite)) return FALSE; // Convert the last-write time to local time. FileTimeToSystemTime(&ftWrite, &stUTC); SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal); // Build a string showing the date and time. wsprintfA(lpszString, "%02d/%02d/%d %02d:%02d", stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute); //!!!!!!!!!!!!!!! return TRUE; } // do lastchecked(file(X)) returns amount of chars to add to str pointer int lastChecked(CMStringA &szNewStr, const char *str) { char *szPattern = "lastchecked(file("; size_t cbPattern = mir_strlen(szPattern); if (!strncmp(str, szPattern, cbPattern)) { int file; char tszFileName[MAX_PATH], temp[MAX_PATH], szSetting[20]; sscanf(&str[cbPattern], "%d", &file); mir_snprintf(szSetting, "fn%d", file); char *szVar = db_get_sa(0, MODNAME, szSetting); if (szVar == nullptr) return 0; if (!strncmp("http://", szVar, 7) || !strncmp("https://", szVar, 8)) mir_snprintf(tszFileName, "%s\\plugins\\fn%d.html", getMimDir(temp), file); else mir_strncpy(tszFileName, szVar, _countof(tszFileName)); mir_free(szVar); HANDLE hFile = CreateFileA(tszFileName, 0, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) return 0; if (GetLastWriteTime(hFile, tszFileName)) { CloseHandle(hFile); szNewStr.Append(tszFileName); mir_snprintf(tszFileName, "%s%d))", szPattern, file); return (int)mir_strlen(tszFileName); } CloseHandle(hFile); } return 0; } // do icon(x) 0=offline, 1=online void checkIcon(MCONTACT hContact, char* string) { char* str = strstr(string, "icon("); if (str) { int icon = getNumber(str + 5); if (icon >= 0) g_plugin.setWord(hContact, "Status", (uint16_t)(ID_STATUS_OFFLINE + icon)); } } int stringReplacer(const char *oldString, CMStringA &szNewString, MCONTACT hContact) { char var_file[8]; int tempInt; int startLine = 0, endLine = 0, startChar = 0, endChar = 0, wholeLine = -1, linesInFile; int positionInOldString = 0; char *fileContents[MAXLINES] = {}, tempString[MAX_STRING_LENGTH]; // setup the variable names szNewString.Empty(); strncpy(var_file, "file(", sizeof(var_file)); while ((positionInOldString < (int)mir_strlen(oldString)) && (oldString[positionInOldString] != '\0')) { // load the file... must be first if (!strncmp(&oldString[positionInOldString], var_file, mir_strlen(var_file))) { positionInOldString += (int)mir_strlen(var_file); // check if its a number tempInt = getNumber(&oldString[positionInOldString]); if (tempInt == -1) { // not a number so check vars.. // there are none yet return ERROR_NO_FILE; } // read the file linesInFile = readFileIntoArray(tempInt, fileContents); if (linesInFile == 0) return ERROR_NO_FILE; positionInOldString += (int)mir_strlen(_itoa(tempInt, tempString, 10)) + 1; // +1 for the closing ) // wholeline() if (!strncmp(&oldString[positionInOldString], "wholeline(line(", mir_strlen("wholeline(line("))) { positionInOldString += (int)mir_strlen("wholeline(line("); tempInt = findLine(fileContents, oldString, linesInFile, startLine, &positionInOldString); if (tempInt == -1 || !fileContents[tempInt]) return ERROR_NO_LINE_AFTER_VAR_F; wholeLine = tempInt; positionInOldString += 3; // add 2 for the )) for wholeline(line()) } if (!strncmp(&oldString[positionInOldString], "start(", mir_strlen("start("))) { positionInOldString += (int)mir_strlen("start(line("); tempInt = findLine(fileContents, oldString, linesInFile, startLine, &positionInOldString); if (tempInt == -1 || !fileContents[tempInt]) return ERROR_NO_LINE_AFTER_VAR_F; else { positionInOldString += 2; startLine = tempInt; if (!endChar) endChar = (int)mir_strlen(fileContents[startLine]); tempInt = findChar(fileContents, oldString, startLine, &positionInOldString, startChar, 0); if (tempInt == -1) return ERROR_NO_LINE_AFTER_VAR_F; startChar = tempInt; } positionInOldString += 2; // add 2 for the )) for start(line()) } if (!strncmp(&oldString[positionInOldString], "end(", mir_strlen("end("))) { positionInOldString += (int)mir_strlen("end(line("); tempInt = findLine(fileContents, oldString, linesInFile, startLine, &positionInOldString); if (tempInt == -1 || !fileContents[tempInt]) return ERROR_NO_LINE_AFTER_VAR_F; positionInOldString += 2; endLine = tempInt; tempInt = findChar(fileContents, oldString, startLine, &positionInOldString, startChar, 1); if (tempInt == -1) return ERROR_NO_LINE_AFTER_VAR_F; endChar = tempInt; positionInOldString += 2; // add 2 for the )) for end(line()) } // check for both start() and end() otherwise, only copying 1 line if (!strstr(oldString, "start(")) startLine = endLine; if (!strstr(oldString, "end(")) endLine = startLine; // after all the options copy the line across and add 2 to positionInOldString for the file(print(....)) if (wholeLine >= 0) szNewString.Append(fileContents[wholeLine]); else { // only copying from 1 line if (startLine == endLine) szNewString.Append(&fileContents[startLine][startChar], endChar - startChar); else { // copy the whole first line from startChar szNewString.Append(&fileContents[startLine][startChar]); // copy the middle lines across for (int i = (startLine + 1); i < endLine; i++) szNewString.Append(fileContents[i]); // copy the last line untill endChar szNewString.Append(fileContents[endLine], endChar); } } } // filename() else if (!strncmp(&oldString[positionInOldString], "filename(", mir_strlen("filename("))) { positionInOldString += (int)mir_strlen("filename("); tempInt = getNumber(&oldString[positionInOldString]); if (tempInt == -1) return ERROR_NO_FILE; mir_snprintf(tempString, "fn%d", tempInt); if (db_get_static(NULL, MODNAME, tempString, tempString, _countof(tempString))) return ERROR_NO_FILE; szNewString.Append(tempString); positionInOldString += (int)mir_strlen(_itoa(tempInt, tempString, 10)) + 1; } // lastchecked(file(X)) else if (!strncmp(&oldString[positionInOldString], "lastchecked(file(", mir_strlen("lastchecked(file("))) { positionInOldString += lastChecked(szNewString, &oldString[positionInOldString]); } else { szNewString.Append(&oldString[positionInOldString], 1); positionInOldString++; } } // free the file strings for (tempInt = 0; (tempInt < MAXLINES) && (fileContents[tempInt] != nullptr); tempInt++) free(fileContents[tempInt]); // check for load("A","B") checkStringForLoad(hContact, szNewString); // and loadN(...) checkStringForLoadN(szNewString); // check for compare("A","B","X","Y") checkStringForcompare(szNewString); // check for save("A","B") checkStringForSave(hContact, szNewString); // and saveN(...) checkStringForSaveN(szNewString); return 1; } void WriteSetting(MCONTACT hContact, char* module1, char* setting1, char* module2, char* setting2) { CMStringA newString; char text[MAX_STRING_LENGTH]; int error = 0, status = GetLCStatus(0, 0); if (!db_get_static(hContact, module1, setting1, text, _countof(text))) { switch (stringReplacer(text, newString, hContact)) { case ERROR_NO_LINE_AFTER_VAR_F: newString.Format(Translate("%s - ERROR: no line specified or line not found (in %s)"), text, setting1); error = 1; break; case ERROR_LINE_NOT_READ: newString.Format(Translate("%s - ERROR: file couldn't be opened (in %s)"), text, setting1); error = 1; break; case ERROR_NO_FILE: newString.Format(Translate("%s - ERROR: no file specified in settings (in %s)"), text, setting1); error = 1; break; default: error = 0; break; } // strip the tab and new lines from all except the tooltip if (!error && mir_strcmp(setting1, "ToolTip")) newString.TrimRight(); db_set_s(hContact, module2, setting2, newString); } else db_set_s(hContact, module2, setting2, ""); if (!error) { if ((status == ID_STATUS_ONLINE) || (status == ID_STATUS_AWAY) || (status == g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE)) || g_plugin.getByte(hContact, "AlwaysVisible", 0)) g_plugin.setWord(hContact, "Status", (uint16_t)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE)); else g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE); } else g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE); } void replaceAllStrings(MCONTACT hContact) { WriteSetting(hContact, MODNAME, "Name", MODNAME, "Nick"); WriteSetting(hContact, MODNAME, "ProgramString", MODNAME, "Program"); WriteSetting(hContact, MODNAME, "ProgramParamsString", MODNAME, "ProgramParams"); /* tooltips*/ WriteSetting(hContact, MODNAME, "ToolTip", "UserInfo", "MyNotes"); char tmp1[256], tmp2[256], tmp3[256]; if (db_get_static(hContact, MODNAME, "Program", tmp1, _countof(tmp1))) db_set_s(hContact, "UserInfo", "FirstName", ""); else if (db_get_static(hContact, MODNAME, "ProgramParams", tmp2, _countof(tmp2))) db_set_s(hContact, "UserInfo", "FirstName", tmp1); else { mir_snprintf(tmp3, "%s %s", tmp1, tmp2); db_set_s(hContact, "UserInfo", "FirstName", tmp3); } }