/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2009 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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. */ #include "..\..\core\commonheaders.h" #include "findadd.h" enum { COLUMNID_PROTO, COLUMNID_HANDLE, COLUMNID_NICK, COLUMNID_FIRST, COLUMNID_LAST, COLUMNID_EMAIL, NUM_COLUMNID }; void SaveColumnSizes(HWND hwndResults) { int columnOrder[NUM_COLUMNID]; int columnCount; char szSetting[32]; int i; struct FindAddDlgData *dat; dat=(struct FindAddDlgData*)GetWindowLongPtr(GetParent(hwndResults),GWLP_USERDATA); columnCount=Header_GetItemCount(ListView_GetHeader(hwndResults)); if (columnCount != NUM_COLUMNID) return; ListView_GetColumnOrderArray(hwndResults,columnCount,columnOrder); for(i=0; i < NUM_COLUMNID; i++) { mir_snprintf(szSetting, SIZEOF(szSetting), "ColOrder%d", i); DBWriteContactSettingByte(NULL,"FindAdd",szSetting,(BYTE)columnOrder[i]); if(i>=columnCount) continue; mir_snprintf(szSetting, SIZEOF(szSetting), "ColWidth%d", i); DBWriteContactSettingWord(NULL,"FindAdd",szSetting,(WORD)ListView_GetColumnWidth(hwndResults,i)); } DBWriteContactSettingByte(NULL,"FindAdd","SortColumn",(BYTE)dat->iLastColumnSortIndex); DBWriteContactSettingByte(NULL,"FindAdd","SortAscending",(BYTE)dat->bSortAscending); } static const TCHAR *szColumnNames[] = { NULL, NULL, _T("Nick"), _T("First Name"), _T("Last Name"), _T("E-mail") }; static int defaultColumnSizes[]={0,90,100,100,100,2000}; void LoadColumnSizes(HWND hwndResults,const char *szProto) { HDITEM hdi; int columnOrder[NUM_COLUMNID]; int columnCount; char szSetting[32]; int i; FindAddDlgData *dat; bool colOrdersValid; defaultColumnSizes[COLUMNID_PROTO] = GetSystemMetrics(SM_CXSMICON) + 4; dat = (FindAddDlgData*)GetWindowLongPtr(GetParent(hwndResults), GWLP_USERDATA); columnCount = NUM_COLUMNID; colOrdersValid = true; for(i=0; i < NUM_COLUMNID; i++) { LVCOLUMN lvc; if( i < columnCount ) { int bNeedsFree = FALSE; lvc.mask = LVCF_TEXT | LVCF_WIDTH; if( szColumnNames[i] != NULL ) lvc.pszText = TranslateTS( szColumnNames[i] ); else if( i == COLUMNID_HANDLE ) { if (szProto) { #if defined( _UNICODE ) bNeedsFree = TRUE; lvc.pszText = mir_a2t((char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0)); #else lvc.pszText = (char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0); #endif } else lvc.pszText = _T("ID"); } else lvc.mask &= ~LVCF_TEXT; mir_snprintf(szSetting, SIZEOF(szSetting), "ColWidth%d", i); lvc.cx = DBGetContactSettingWord(NULL, "FindAdd", szSetting, defaultColumnSizes[i]); ListView_InsertColumn(hwndResults, i, (LPARAM)&lvc); #if defined( _UNICODE ) if (bNeedsFree) mir_free(lvc.pszText); #endif } mir_snprintf(szSetting, SIZEOF(szSetting), "ColOrder%d", i); columnOrder[i] = DBGetContactSettingByte(NULL, "FindAdd", szSetting, -1); if (columnOrder[i] == -1 || columnOrder[i] >= NUM_COLUMNID) colOrdersValid = false; } if (colOrdersValid) ListView_SetColumnOrderArray(hwndResults, columnCount, columnOrder); dat->iLastColumnSortIndex = DBGetContactSettingByte(NULL, "FindAdd", "SortColumn", COLUMNID_NICK); if (dat->iLastColumnSortIndex >= columnCount) dat->iLastColumnSortIndex = COLUMNID_NICK; dat->bSortAscending = DBGetContactSettingByte(NULL, "FindAdd", "SortAscending", TRUE); hdi.mask = HDI_BITMAP | HDI_FORMAT; hdi.fmt = HDF_LEFT | HDF_BITMAP | HDF_STRING | HDF_BITMAP_ON_RIGHT; hdi.hbm = dat->bSortAscending ? dat->hBmpSortDown : dat->hBmpSortUp; Header_SetItem(ListView_GetHeader(hwndResults), dat->iLastColumnSortIndex, &hdi); } static LPARAM ListView_GetItemLParam(HWND hwndList, int idx) { LVITEM lv; lv.iItem = idx; lv.mask = LVIF_PARAM; ListView_GetItem(hwndList,&lv); return lv.lParam; } int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { struct FindAddDlgData *dat=(struct FindAddDlgData*)GetWindowLongPtr((HWND) lParamSort, GWLP_USERDATA); int sortMultiplier; int sortCol; struct ListSearchResult *lsr1, *lsr2; HWND hList=GetDlgItem((HWND) lParamSort, IDC_RESULTS); sortMultiplier=dat->bSortAscending?1:-1; sortCol=dat->iLastColumnSortIndex; if (!dat->bFlexSearchResult) { lsr1=(struct ListSearchResult*)ListView_GetItemLParam(hList, (int)lParam1); lsr2=(struct ListSearchResult*)ListView_GetItemLParam(hList, (int)lParam2); if ( lsr1 == NULL || lsr2 == NULL ) return 0; switch(sortCol) { case COLUMNID_PROTO: return lstrcmpA(lsr1->szProto, lsr2->szProto)*sortMultiplier; case COLUMNID_HANDLE: return lstrcmpi(lsr1->psr.id, lsr2->psr.id)*sortMultiplier; case COLUMNID_NICK: return lstrcmpi(lsr1->psr.nick, lsr2->psr.nick)*sortMultiplier; case COLUMNID_FIRST: return lstrcmpi(lsr1->psr.firstName, lsr2->psr.firstName)*sortMultiplier; case COLUMNID_LAST: return lstrcmpi(lsr1->psr.lastName, lsr2->psr.lastName)*sortMultiplier; case COLUMNID_EMAIL: return lstrcmpi(lsr1->psr.email, lsr2->psr.email)*sortMultiplier; } } else { TCHAR szText1[100]; TCHAR szText2[100]; ListView_GetItemText(hList,(int)lParam1,sortCol,szText1,SIZEOF(szText1)); ListView_GetItemText(hList,(int)lParam2,sortCol,szText2,SIZEOF(szText2)); return _tcsicmp(szText1, szText2)*sortMultiplier; } return 0; } void FreeSearchResults(HWND hwndResults) { LV_ITEM lvi; struct ListSearchResult *lsr; for(lvi.iItem=ListView_GetItemCount(hwndResults)-1;lvi.iItem>=0;lvi.iItem--) { lvi.mask=LVIF_PARAM; ListView_GetItem(hwndResults,&lvi); lsr=(struct ListSearchResult*)lvi.lParam; if(lsr==NULL) continue; mir_free(lsr->psr.id); mir_free(lsr->psr.email); mir_free(lsr->psr.nick); mir_free(lsr->psr.firstName); mir_free(lsr->psr.lastName); mir_free(lsr); } ListView_DeleteAllItems(hwndResults); EnableResultButtons(GetParent(hwndResults),0); } // on its own thread static void BeginSearchFailed(void * arg) { TCHAR buf[128]; if ( arg != NULL ) { const TCHAR* protoName = (TCHAR*)arg; mir_sntprintf(buf,SIZEOF(buf), TranslateT("Could not start a search on '%s', there was a problem - is %s connected?"), protoName,protoName); mir_free((char*)arg); } else lstrcpyn(buf,TranslateT("Could not search on any of the protocols, are you online?"),SIZEOF(buf)); MessageBox(0,buf,TranslateT("Problem with search"),MB_OK | MB_ICONERROR); } int BeginSearch(HWND,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams) { int i; if ( szProto == NULL ) { int failures = 0; dat->searchCount = 0; dat->search = (struct ProtoSearchInfo*)mir_calloc(sizeof(struct ProtoSearchInfo) * accounts.getCount()); for( i=0; i < accounts.getCount();i++) { PROTOACCOUNT* pa = accounts[i]; if (!Proto_IsAccountEnabled(pa)) continue; DWORD caps=(DWORD)CallProtoService(pa->szModuleName,PS_GETCAPS,PFLAGNUM_1,0); if(!(caps&requiredCapability)) continue; dat->search[dat->searchCount].hProcess = (HANDLE)CallProtoService(pa->szModuleName,szSearchService,0,(LPARAM)pvSearchParams); dat->search[dat->searchCount].szProto = pa->szModuleName; if ( dat->search[dat->searchCount].hProcess == NULL ) failures++; else dat->searchCount++; } if(failures) { //infuriatingly vague error message. fixme. if(dat->searchCount==0) { forkthread(BeginSearchFailed,0,NULL); mir_free(dat->search); dat->search=NULL; return 1; } } } else { dat->search=(struct ProtoSearchInfo*)mir_alloc(sizeof(struct ProtoSearchInfo)); dat->searchCount=1; dat->search[0].hProcess=(HANDLE)CallProtoService(szProto,szSearchService,0,(LPARAM)pvSearchParams); dat->search[0].szProto=szProto; if(dat->search[0].hProcess==NULL) { //infuriatingly vague error message. fixme. PROTOACCOUNT* pa = Proto_GetAccount(szProto); forkthread(BeginSearchFailed, 0, mir_tstrdup(pa->tszAccountName)); mir_free(dat->search); dat->search=NULL; dat->searchCount=0; return 1; } } return 0; } // !!!!!!!! this code is dangerous like a hell void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat) { TCHAR str[256]; if (dat->searchCount != 0 ) { int i; lstrcpy( str, TranslateT("Searching")); for( i=0; i < dat->searchCount; i++ ) { PROTOACCOUNT* pa = Proto_GetAccount( dat->search[i].szProto ); if ( !pa ) continue; lstrcat(str, i ? _T(",") : _T( " " )); lstrcat(str, pa->tszAccountName ); } } else lstrcpy(str, TranslateT("Idle")); SendMessage( hwndStatus, SB_SETTEXT, 0, (LPARAM)str ); } struct ProtoResultsSummary { const char *szProto; int count; }; void SetStatusBarResultInfo(HWND hwndDlg) { HWND hwndStatus=GetDlgItem(hwndDlg,IDC_STATUSBAR); HWND hwndResults=GetDlgItem(hwndDlg,IDC_RESULTS); LV_ITEM lvi; struct ListSearchResult *lsr; struct ProtoResultsSummary *subtotal=NULL; int subtotalCount=0; int i,total; TCHAR str[256]; total=ListView_GetItemCount(hwndResults); for(lvi.iItem=total-1;lvi.iItem>=0;lvi.iItem--) { lvi.mask=LVIF_PARAM; ListView_GetItem(hwndResults,&lvi); lsr=(struct ListSearchResult*)lvi.lParam; if(lsr==NULL) continue; for(i=0;iszProto) { subtotal[i].count++; break; } } if(i==subtotalCount) { subtotal=(struct ProtoResultsSummary*)mir_realloc(subtotal,sizeof(struct ProtoResultsSummary)*(subtotalCount+1)); subtotal[subtotalCount].szProto=lsr->szProto; subtotal[subtotalCount++].count=1; } } if ( total != 0 ) { TCHAR substr[64]; PROTOACCOUNT* pa = Proto_GetAccount( subtotal[0].szProto ); if ( pa == NULL ) return; if ( subtotalCount == 1 ) { if(total==1) mir_sntprintf( str, SIZEOF(str), TranslateT("1 %s user found"), pa->tszAccountName ); else mir_sntprintf( str, SIZEOF(str), TranslateT("%d %s users found"), total, pa->tszAccountName ); } else { mir_sntprintf( str, SIZEOF(str), TranslateT("%d users found ("),total); for( i=0; i < subtotalCount; i++ ) { if ( i ) { if (( pa = Proto_GetAccount( subtotal[i].szProto )) == NULL ) return; lstrcat( str, _T(", ")); } mir_sntprintf( substr, SIZEOF(substr), _T("%d %s"), subtotal[i].count, pa->tszAccountName ); lstrcat( str, substr ); } lstrcat( str, _T(")")); } mir_free(subtotal); } else lstrcpy(str, TranslateT("No users found")); SendMessage(hwndStatus, SB_SETTEXT, 2, (LPARAM)str ); } void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto) { SaveColumnSizes(hwndResults); while(ListView_DeleteColumn(hwndResults,0)); ListView_SetImageList(hwndResults,dat->himlComboIcons,LVSIL_SMALL); LoadColumnSizes(hwndResults,szProto); } void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y) { struct FindAddDlgData *dat; HMENU hPopupMenu,hMenu; int commandId; struct ListSearchResult *lsr; dat=(struct FindAddDlgData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); { LVITEM lvi; if(ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS))!=1) return; lvi.mask=LVIF_PARAM; lvi.iItem=ListView_GetNextItem(GetDlgItem(hwndDlg,IDC_RESULTS),-1,LVNI_ALL|LVNI_SELECTED); ListView_GetItem(GetDlgItem(hwndDlg,IDC_RESULTS),&lvi); lsr=(struct ListSearchResult*)lvi.lParam; } hMenu=LoadMenu(hMirandaInst,MAKEINTRESOURCE(IDR_CONTEXT)); hPopupMenu=GetSubMenu(hMenu,4); CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hPopupMenu,0); commandId=TrackPopupMenu(hPopupMenu,TPM_RIGHTBUTTON|TPM_RETURNCMD,x,y,0,hwndDlg,NULL); switch(commandId) { case IDC_ADD: { ADDCONTACTSTRUCT acs; acs.handle=NULL; acs.handleType=HANDLE_SEARCHRESULT; acs.szProto=lsr->szProto; acs.psr=&lsr->psr; CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs); break; } case IDC_DETAILS: { HANDLE hContact; hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr); CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)hContact,0); break; } case IDC_SENDMESSAGE: { HANDLE hContact; hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr); CallService(MS_MSG_SENDMESSAGE,(WPARAM)hContact,(LPARAM)(const char*)NULL); break; } } DestroyMenu(hPopupMenu); DestroyMenu(hMenu); }