/* Weather Protocol plugin for Miranda IM Copyright (C) 2005-2011 Boris Krasnovskiy All Rights Reserved Copyright (C) 2002-2005 Calvin Che 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; version 2 of the License. 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, see . */ /* This file contain the source related unit conversion, icon assignment, string conversions, display text parsing, etc */ #include "weather.h" //============ SOME HELPER FUNCTIONS ============ // see if a string is a number // s = the string to be determined // return value = true if the string is a number, false if it isn't BOOL is_number(char *s) { BOOL tag = FALSE; // looking character by character // for a number: numerous spaces in front, then optional +/-, then the number // don't care anything that comes after it while(*s != '\0') { if (*s >= '0' && *s <='9') return TRUE; else if (*s == ' '); else if (*s != '+' && *s != '-') return FALSE; else if ((*s == '+' || *s == '-') && !tag) tag = TRUE; else return FALSE; s++; } return FALSE; } static void numToStr(double num, char* str) { int i = (int)(num * (opt.NoFrac ? 10 : 100)); int u = abs(i); int r = u % 10; int w = u / 10 + (r >= 5); if (opt.NoFrac) { r = 0; } else { r = w % 10; w /= 10; } if (i < 0 && (w || r)) *(str++) = '-'; if (r) sprintf(str, "%i.%i", w, r); else sprintf(str, "%i", w); } //============ UNIT CONVERSIONS ============ // temperature conversion // tempchar = the string containing the temperature value // unit = the unit for temperature // return value = the converted temperature with degree sign and unit; if fails, return N/A void GetTemp(char *tempchar, char *unit, char* str) { // unit can be C, F double temp; char tstr[20]; TrimString(tempchar); if (tempchar[0] == '-' && tempchar[1] == ' ') memmove(&tempchar[1], &tempchar[2], strlen(&tempchar[2])+1); // quit if the value obtained is N/A or not a number if (!strcmp(tempchar, NODATA) || !strcmp(tempchar, "N/A")) { strcpy(str, tempchar); return; } if (!is_number(tempchar)) { strcpy(str, NODATA); return; } // convert the string to an integer temp = atof(tempchar); // convert all to F first if (!_stricmp(unit, "C")) temp = (temp*9/5)+32; else if (!_stricmp(unit, "K")) temp = ((temp-273.15)*9/5)+32; // convert to apporiate unit switch (opt.tUnit) { case 1: // rounding numToStr((temp-32)/9*5, tstr); if (opt.DoNotAppendUnit) sprintf(str, "%s", tstr); else sprintf(str, "%s%sC", tstr, opt.DegreeSign); break; case 2: numToStr(temp, tstr); if (opt.DoNotAppendUnit) sprintf(str, "%s", tstr); else sprintf(str, "%s%sF", tstr, opt.DegreeSign); break; } } // temperature conversion // tempchar = the string containing the pressure value // unit = the unit for pressure // return value = the converted pressure with unit; if fail, return the original string void GetPressure(char *tempchar, char *unit, char* str) { // unit can be kPa, hPa, mb, in, mm, torr double tempunit = 0, output; int intunit; // convert the string to a floating point number (always positive) // if it end up with 0, then it's not a number, return the original string and quit output = atof(tempchar); if (output == 0) { strcpy(str, tempchar); return; } // convert all to mb first if (!_stricmp(unit, "KPA")) tempunit = (double)output * 10; else if (!_stricmp(unit, "HPA")) tempunit = (double)output; else if (!_stricmp(unit, "MB")) tempunit = (double)output; else if (!_stricmp(unit, "IN")) tempunit = (double)output * 33.86388; else if (!_stricmp(unit, "MM")) tempunit = (double)output * 1.33322; else if (!_stricmp(unit, "TORR")) tempunit = (double)output * 1.33322; // convert to apporiate unit switch (opt.pUnit) { case 1: intunit = (int)(tempunit + 0.5); wsprintf(str, "%i.%i %s", intunit/10, intunit%10, opt.DoNotAppendUnit ? "" : Translate("kPa")); break; case 2: intunit = (int)(tempunit + 0.5); wsprintf(str, "%i %s", intunit, opt.DoNotAppendUnit ? "" : Translate("mb")); break; case 3: intunit = (int)((tempunit*10 / 33.86388) + 0.5); wsprintf(str, "%i.%i %s", intunit/10, intunit%10, opt.DoNotAppendUnit ? "" : Translate("in")); break; case 4: intunit = (int)((tempunit*10 / 1.33322) + 0.5); wsprintf(str, "%i.%i %s", intunit/10, intunit%10, opt.DoNotAppendUnit ? "" : Translate("mm")); break; default: strcpy(str, tempchar); break; } } // speed conversion // tempchar = the string containing the speed value // unit = the unit for speed // return value = the converted speed with unit; if fail, return "" void GetSpeed(char *tempchar, char *unit, char *str) { // unit can be km/h, mph, m/s, knots double tempunit; char tstr[20]; str[0] = 0; // convert the string into an integer (always positive) // if the result is 0, then the string is not a number, return "" tempunit = atof(tempchar); if (tempunit == 0 && tempchar[0] != '0') return; // convert all to m/s first if (!_stricmp(unit, "KM/H")) tempunit /= 3.6; // else if (!_stricmp(unit, "M/S")) // tempunit = tempunit; else if (!_stricmp(unit, "MPH")) tempunit *= 0.44704; else if (!_stricmp(unit, "KNOTS")) tempunit *= 0.514444; // convert to apporiate unit switch (opt.wUnit) { case 1: numToStr(tempunit * 3.6, tstr); sprintf(str, "%s %s", tstr, opt.DoNotAppendUnit ? "" : Translate("km/h")); break; case 2: numToStr(tempunit, tstr); sprintf(str, "%s %s", tstr, opt.DoNotAppendUnit ? "" : Translate("m/s")); break; case 3: numToStr(tempunit / 0.44704, tstr); sprintf(str, "%s %s", tstr, opt.DoNotAppendUnit ? "" : Translate("mph")); break; case 4: numToStr(tempunit / 0.514444, tstr); sprintf(str, "%s %s", tstr, opt.DoNotAppendUnit ? "" : Translate("knots")); break; } } // distance conversion // tempchar = the string containing the distance value // unit = the unit for distance // return value = the converted distance with unit; if fail, return original string void GetDist(char *tempchar, char *unit, char *str) { // unit can be km, miles double tempunit = 0, output; int intunit; // convert the string to a floating point number (always positive) // if it end up with 0, then it's not a number, return the original string and quit output = atof(tempchar); if (output == 0) { strcpy(str, tempchar); return; } // convert all to km first if (!_stricmp(unit, "KM")) tempunit = (double)output; else if (!_stricmp(unit, "MILES")) tempunit = (double)output * 1.609; // convert to apporiate unit switch (opt.vUnit) { case 1: intunit = (int)((tempunit*10) + 0.5); wsprintf(str, "%i.%i %s", intunit/10, intunit%10, opt.DoNotAppendUnit ? "" : Translate("km")); break; case 2: intunit = (int)((tempunit*10 / 1.609) + 0.5); wsprintf(str, "%i.%i %s", intunit/10, intunit%10, opt.DoNotAppendUnit ? "" : Translate("miles")); break; default: strcpy(str, tempchar); break; } } //============ CONDITION ICON ASSIGNMENT ============ // assign the contact icon (status) from the condition string // the description may be different between different sources // cond = the string for weather condition // return value = status for the icon (ONLINE, OFFLINE, etc) WORD GetIcon(const char* cond, WIDATA *Data) { int i; static const char *statusStr[10] = { "Lightning", "Fog", "Snow Shower", "Snow", "Rain Shower", "Rain", "Partly Cloudy", "Cloudy", "Sunny", "N/A" }; static const WORD statusValue[10] = { LIGHT, FOG, SSHOWER, SNOW, RSHOWER, RAIN, PCLOUDY, CLOUDY, SUNNY, NA }; // set the icon using ini for (i=0; i<10; i++) { if (IsContainedInCondList(cond, &Data->CondList[i])) return statusValue[i]; } // internal detection if ( strstr(cond, "mainy sunny") != NULL || strstr(cond, "mainy clear") != NULL || strstr(cond, "partly cloudy") != NULL || strstr(cond, "mostly") != NULL || strstr(cond, "clouds") != NULL) { return PCLOUDY; } else if ( strstr(cond, "sunny") != NULL || strstr(cond, "clear") != NULL || strstr(cond, "fair") != NULL) { return SUNNY; } else if ( strstr(cond, "thunder") != NULL || strstr(cond, "t-storm") != NULL) { return LIGHT; } else if ( strstr(cond, "cloud") != NULL || strstr(cond, "overcast") != NULL) { return CLOUDY; } else if ( strstr(cond, "fog") != NULL || strstr(cond, "mist") != NULL || strstr(cond, "smoke") != NULL || strstr(cond, "sand") != NULL || strstr(cond, "dust") != NULL || strstr(cond, "haze") != NULL) { return FOG; } else if ( (strstr(cond, "shower") != NULL && strstr(cond, "snow") != NULL) || strstr(cond, "flurries") != NULL) { return SSHOWER; } else if ( strstr(cond, "rain shower") != NULL || strstr(cond, "shower") != NULL) { return RSHOWER; } else if ( strstr(cond, "snow") != NULL || strstr(cond, "ice") != NULL || strstr(cond, "freezing") != NULL || strstr(cond, "wintry") != NULL) { return SNOW; } else if ( strstr(cond, "drizzle") != NULL || strstr(cond, "rain") != NULL) { return RAIN; } // set the icon using langpack for (i=0; i<9; i++) { char LangPackStr[64]; char LangPackStr1[128]; int j = 0; do { j++; // using the format "# Weather #" mir_snprintf(LangPackStr, sizeof(LangPackStr), "# Weather %s %i #", statusStr[i], j); mir_snprintf(LangPackStr1, sizeof(LangPackStr1), "%s", Translate(LangPackStr)); CharLowerBuff(LangPackStr1, (DWORD)strlen(LangPackStr1)); if (strstr(cond, LangPackStr1) != NULL) return statusValue[i]; // loop until the translation string exists (ie, the translated string is differ from original) } while (strcmp(Translate(LangPackStr), LangPackStr)); } return NA; } //============ STRING CONVERSIONS ============ // language pack can't translate str with /r; text box can't display properly for str without /r void FixStr(const char *orig, char* str) { size_t i, ci = 0, li = strlen(orig); for (i = 0; i < li; i++) { if (orig[i] == '\n') str[ci++] = '\r'; str[ci++] = orig[i]; } str[ci] = 0; } // this function convert the string to the format with 1 upper case followed by lower case char void CaseConv(char *str) { char *pstr; BOOL nextUp = TRUE; CharLowerBuff(str, (DWORD)strlen(str)); for(pstr=str; *pstr; pstr++) { if (*pstr==' ' || *pstr=='-') nextUp = TRUE; else { unsigned ch = *(unsigned char*)pstr; if (nextUp) *pstr = (char)(unsigned)CharUpper((LPSTR)ch); nextUp = FALSE; } } } // the next 2 functions are copied from miranda source // str = the string to modify void TrimString(char *str) { size_t len, start; len = strlen(str); while(len && (unsigned char)str[len-1] <= ' ') str[--len] = 0; for(start=0; (unsigned char)str[start]<=' ' && str[start]; start++); memmove(str, str+start, len-start+1); } // convert \t to tab and \n to linefeed void ConvertBackslashes(char *str) { char *pstr; for(pstr=str;*pstr;pstr=CharNext(pstr)) { if(*pstr=='\\') { switch(pstr[1]) { case 'n': *pstr='\n'; break; case 't': *pstr='\t'; break; default: *pstr=pstr[1]; break; } memmove(pstr+1,pstr+2,strlen(pstr+2)+1); } } } // replace spaces with "%20" // dis = original string // return value = the modified string with space -> "%20" char *GetSearchStr(char *dis) { char *pstr = dis; size_t len = strlen(dis); while (*pstr != 0) { if (*pstr == ' ') { memmove(pstr+3, pstr+1, len); memcpy(pstr, "%20", 3); pstr += 2; } pstr++; len--; } return dis; } //============ ICON ASSIGNMENT ============ // make display and history strings // w = WEATHERINFO data to be parsed // dis = the string to parse // return value = the parsed string char* GetDisplay(WEATHERINFO *w, const char *dis, char* str) { char lpzDate[32], chr, name[256], temp[2]; DBVARIANT dbv; size_t i; // Clear the string str[0] = 0; // looking character by character for (i=0; icond); break; case 'd': // get the current date GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, lpzDate, sizeof(lpzDate)); strcat(str, lpzDate); break; case 'e': strcat(str, w->dewpoint); break; case 'f': strcat(str, w->feel); break; case 'h': strcat(str, w->high); break; case 'i': strcat(str, w->winddir); break; case 'l': strcat(str, w->low); break; case 'm': strcat(str, w->humid); break; case 'n': strcat(str, w->city); break; case 'p': strcat(str, w->pressure); break; case 'r': strcat(str, w->sunrise); break; case 's': strcat(str, w->id); break; case 't': strcat(str, w->temp); break; case 'u': if (strcmp(w->update, NODATA)) strcat(str, w->update); else strcat(str, Translate("")); break; case 'v': strcat(str, w->vis); break; case 'w': strcat(str, w->wind); break; case 'y': strcat(str, w->sunset); break; case '%': strcat(str, "%"); break; case '[': // custom variables i++; name[0] = 0; // read the entire variable name while (dis[i] != ']' && i < strlen(dis)) { wsprintf(temp, "%c", dis[i++]); strcat(name, temp); } // access the database to get its value if (!DBGetContactSettingString(w->hContact, WEATHERCONDITION, name, &dbv)) { if (dbv.pszVal != Translate(NODATA) && dbv.pszVal != Translate("")) strcat(str, dbv.pszVal); DBFreeVariant(&dbv); } break; } } // if the character is not a variable, write the original character to the new string else { wsprintf(temp, "%c", dis[i]); strcat(str, temp); } } return str; } char svcReturnText[MAX_TEXT_SIZE]; INT_PTR GetDisplaySvcFunc(WPARAM wParam, LPARAM lParam) { WEATHERINFO winfo = LoadWeatherInfo((HANDLE)wParam); return (INT_PTR)GetDisplay(&winfo, (char *)lParam, svcReturnText); } //============ ID MANAGEMENT ============ // get service data module internal name // mod/id <- the mod part // pszID = original 2-part id, return the service internal name void GetSvc(char *pszID) { char *chop; chop = strstr(pszID, "/"); if (chop != NULL) *chop = '\0'; else pszID[0] = 0; } // get the id use for update without the service internal name // mod/id <- the id part // pszID = original 2-part id, return the single part id void GetID(char *pszID) { char *chop; chop = strstr(pszID, "/"); if (chop != NULL) strcpy(pszID, chop+1); else pszID[0] = 0; } //============ WEATHER ERROR CODE ============ // Get the text when an error code is specified // code = the error code obtained when updating weather // str = the string for the error char *GetError(int code) { char *str, str2[100]; switch (code) { case 10: str = E10; break; case 11: str = E11; break; case 12: str = E12; break; case 20: str = E20; break; case 30: str = E30; break; case 40: str = E40; break; case 42: str = E42; break; case 43: str = E43; break; case 99: str = E99; break; case 204: str = E204; break; case 301: str = E301; break; case 305: str = E305; break; case 307: str = E307; break; case 400: str = E400; break; case 401: str = E401; break; case 402: str = E402; break; case 403: str = E403; break; case 404: str = E404; break; case 405: str = E405; break; case 407: str = E407; break; case 410: str = E410; break; case 500: str = E500; break; case 502: str = E502; break; case 503: str = E503; break; case 504: str = E504; break; default: mir_snprintf(str2, sizeof(str2), Translate("HTTP Error %i"), code); str = str2; break; } return str; } LPWSTR ConvToUnicode(LPCSTR str2) { const size_t nLength = MultiByteToWideChar(lpcp, 0, str2, -1, NULL, 0); LPWSTR res = mir_alloc(sizeof(WCHAR)*nLength); MultiByteToWideChar(lpcp, 0, str2, -1, res, (int)nLength); return res; } typedef BOOL (WINAPI *ft_SetDlgItemTextW) ( HWND hDlg, int nIDDlgItem, LPCWSTR lpString ); typedef BOOL (WINAPI *ft_SetWindowTextW) ( HWND hWnd, LPCWSTR lpString ); typedef UINT (WINAPI *ft_GetDlgItemTextW) ( HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount ); static ft_GetDlgItemTextW f_GetDlgItemTextW = NULL; static ft_SetDlgItemTextW f_SetDlgItemTextW = NULL; static ft_SetWindowTextW f_SetWindowTextW = NULL; unsigned lpcp; void InitUniConv(void) { HMODULE hUser = GetModuleHandle("user32.dll"); f_GetDlgItemTextW = (ft_GetDlgItemTextW)GetProcAddress(hUser, "GetDlgItemTextW"); f_SetDlgItemTextW = (ft_SetDlgItemTextW)GetProcAddress(hUser, "SetDlgItemTextW"); f_SetWindowTextW = (ft_SetWindowTextW) GetProcAddress(hUser, "SetWindowTextW"); lpcp = (unsigned)CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); if (lpcp == CALLSERVICE_NOTFOUND || lpcp == GetUserDefaultLangID()) lpcp = CP_ACP; } UINT GetDlgItemTextWth(HWND hDlg, int nIDDlgItem, LPSTR lpString, int nMaxCount) { UINT res; if (lpcp != CP_ACP && f_GetDlgItemTextW != NULL) { LPWSTR m_psz = mir_alloc(sizeof(WCHAR) * nMaxCount); res = f_GetDlgItemTextW(hDlg, nIDDlgItem, m_psz, nMaxCount); WideCharToMultiByte( lpcp, 0, m_psz, -1, lpString, nMaxCount, NULL, NULL ); mir_free(m_psz); } else res = GetDlgItemText(hDlg, nIDDlgItem, lpString, nMaxCount); return res; } BOOL SetDlgItemTextWth(HWND hDlg, int nIDDlgItem, LPCSTR lpString) { BOOL res; if (lpcp != CP_ACP && f_SetDlgItemTextW != NULL) { LPWSTR m_psz = ConvToUnicode(lpString); res = f_SetDlgItemTextW(hDlg, nIDDlgItem, m_psz); mir_free(m_psz); } else res = SetDlgItemText(hDlg, nIDDlgItem, lpString); return res; } BOOL SetWindowTextWth(HWND hWnd, LPCSTR lpString) { BOOL res; if (lpcp != CP_ACP && f_SetWindowTextW != NULL) { LPWSTR m_psz = ConvToUnicode(lpString); res = f_SetWindowTextW(hWnd, m_psz); mir_free(m_psz); } else res = SetWindowText(hWnd, lpString); return res; } void ListView_SetItemTextWth(HWND hwndLV, int i, int iSubItem_, LPSTR pszText_) { LV_ITEM _ms_lvi; _ms_lvi.iSubItem = iSubItem_; if (lpcp != CP_ACP) { LPWSTR m_psz = ConvToUnicode(pszText_); _ms_lvi.pszText = (LPSTR)m_psz; SendMessage(hwndLV, LVM_SETITEMTEXTW, (WPARAM)(i), (LPARAM)&_ms_lvi); mir_free(m_psz); } else { _ms_lvi.pszText = pszText_; SendMessage(hwndLV, LVM_SETITEMTEXTA, (WPARAM)(i), (LPARAM)&_ms_lvi); } } int ListView_InsertItemWth(HWND hwnd, LV_ITEM *pitem) { int res; if (lpcp != CP_ACP) { LPSTR otxt = pitem->pszText; LPWSTR m_psz = ConvToUnicode(otxt); pitem->pszText = (LPSTR)m_psz; res = SendMessage(hwnd, LVM_INSERTITEMW, 0, (LPARAM)pitem); mir_free(m_psz); pitem->pszText = otxt; } else res = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)pitem); return res; } int ListView_InsertColumnWth(HWND hwnd, int iCol, LV_COLUMN *pitem) { int res; if (lpcp != CP_ACP) { LPSTR otxt = pitem->pszText; LPWSTR m_psz = ConvToUnicode(otxt); pitem->pszText = (LPSTR)m_psz; res = SendMessage(hwnd, LVM_INSERTCOLUMNW, iCol, (LPARAM)pitem); mir_free(m_psz); pitem->pszText = otxt; } else res = SendMessage(hwnd, LVM_INSERTCOLUMNA, iCol, (LPARAM)pitem); return res; }