/* 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 "commonheaders.h" #include "file.h" #define MAX_MRU_DIRS 5 static BOOL CALLBACK ClipSiblingsChildEnumProc(HWND hwnd, LPARAM) { SetWindowLongPtr(hwnd,GWL_STYLE,GetWindowLongPtr(hwnd,GWL_STYLE)|WS_CLIPSIBLINGS); return TRUE; } static void GetLowestExistingDirName(const TCHAR *szTestDir,TCHAR *szExistingDir,int cchExistingDir) { DWORD dwAttributes; TCHAR *pszLastBackslash; lstrcpyn(szExistingDir,szTestDir,cchExistingDir); while((dwAttributes=GetFileAttributes(szExistingDir))!=INVALID_FILE_ATTRIBUTES && !(dwAttributes&FILE_ATTRIBUTE_DIRECTORY)) { pszLastBackslash=_tcsrchr(szExistingDir,'\\'); if(pszLastBackslash==NULL) {*szExistingDir='\0'; break;} *pszLastBackslash='\0'; } if(szExistingDir[0]=='\0') GetCurrentDirectory(cchExistingDir,szExistingDir); } static const TCHAR InvalidFilenameChars[] = _T("\\/:*?\"<>|"); void RemoveInvalidFilenameChars(TCHAR *tszString) { size_t i; if (tszString) { for(i=_tcscspn(tszString,InvalidFilenameChars); tszString[i]; i+=_tcscspn(tszString+i+1,InvalidFilenameChars)+1) if(tszString[i] >= 0) tszString[i] = _T('_'); } } static const TCHAR InvalidPathChars[] = _T("*?\"<>|"); // "\/:" are excluded as they are allowed in file path void RemoveInvalidPathChars(TCHAR *tszString) { size_t i; if (tszString) { for(i=_tcscspn(tszString,InvalidPathChars); tszString[i]; i+=_tcscspn(tszString+i+1,InvalidPathChars)+1) if(tszString[i] >= 0) tszString[i] = _T('_'); } } static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { TCHAR szDir[MAX_PATH]; switch(uMsg) { case BFFM_INITIALIZED: SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData); break; case BFFM_SELCHANGED: if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir)) SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir); break; } return 0; } int BrowseForFolder(HWND hwnd,TCHAR *szPath) { BROWSEINFO bi={0}; LPITEMIDLIST pidlResult; bi.hwndOwner=hwnd; bi.pszDisplayName=szPath; bi.lpszTitle=TranslateT("Select Folder"); bi.ulFlags=BIF_NEWDIALOGSTYLE|BIF_EDITBOX|BIF_RETURNONLYFSDIRS; // Use this combo instead of BIF_USENEWUI bi.lpfn=BrowseCallbackProc; bi.lParam=(LPARAM)szPath; pidlResult=SHBrowseForFolder(&bi); if(pidlResult) { SHGetPathFromIDList(pidlResult,szPath); lstrcat(szPath,_T("\\")); CoTaskMemFree(pidlResult); } return pidlResult != NULL; } static REPLACEVARSARRAY sttVarsToReplace[] = { { ( TCHAR* )"///", ( TCHAR* )"//" }, { ( TCHAR* )"//", ( TCHAR* )"/" }, { ( TCHAR* )"()", ( TCHAR* )"" }, { NULL, NULL } }; static void patchDir( TCHAR* str, size_t strSize ) { REPLACEVARSDATA dat = { 0 }; dat.cbSize = sizeof( dat ); dat.dwFlags = RVF_TCHAR; dat.variables = sttVarsToReplace; TCHAR* result = ( TCHAR* )CallService( MS_UTILS_REPLACEVARS, (WPARAM)str, (LPARAM)&dat ); if ( result ) { _tcsncpy( str, result, strSize ); mir_free( result ); } size_t len = lstrlen( str ); if ( len+1 < strSize && str[len-1] != '\\' ) lstrcpy( str+len, _T("\\") ); } void GetContactReceivedFilesDir(HANDLE hContact, TCHAR *szDir, int cchDir, BOOL patchVars) { DBVARIANT dbv; TCHAR szTemp[MAX_PATH]; szTemp[0] = 0; if ( !DBGetContactSettingTString( NULL, "SRFile", "RecvFilesDirAdv", &dbv)) { if ( lstrlen( dbv.ptszVal ) > 0 ) lstrcpyn( szTemp, dbv.ptszVal, SIZEOF( szTemp )); DBFreeVariant( &dbv ); } if ( !szTemp[0] ) #ifdef _UNICODE mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s\\%%userid%%"), TranslateT("My Received Files")); #else mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s\\%%userid%%"), "My Received Files"); #endif if ( hContact ) { REPLACEVARSDATA dat = { 0 }; REPLACEVARSARRAY rvaVarsToReplace[4]; rvaVarsToReplace[0].lptzKey = _T("nick"); rvaVarsToReplace[0].lptzValue = mir_tstrdup((TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)); rvaVarsToReplace[1].lptzKey = _T("userid"); rvaVarsToReplace[1].lptzValue = GetContactID(hContact); rvaVarsToReplace[2].lptzKey = _T("proto"); rvaVarsToReplace[2].lptzValue = mir_a2t((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact,0)); rvaVarsToReplace[3].lptzKey = NULL; rvaVarsToReplace[3].lptzValue = NULL; for (int i=0; i < (SIZEOF(rvaVarsToReplace)-1);i++) RemoveInvalidFilenameChars(rvaVarsToReplace[i].lptzValue); dat.cbSize = sizeof( dat ); dat.dwFlags = RVF_TCHAR; dat.variables = rvaVarsToReplace; dat.hContact = hContact; TCHAR* result = ( TCHAR* )CallService( MS_UTILS_REPLACEVARS, (WPARAM)szTemp, (LPARAM)&dat ); if ( result ) { _tcsncpy( szTemp, result, SIZEOF(szTemp)); mir_free( result ); for (int i=0; i < (SIZEOF(rvaVarsToReplace)-1);i++) mir_free(rvaVarsToReplace[i].lptzValue); } } if (patchVars) patchDir( szTemp, SIZEOF(szTemp)); RemoveInvalidPathChars(szTemp); lstrcpyn( szDir, szTemp, cchDir ); } void GetReceivedFilesDir(TCHAR *szDir, int cchDir) { DBVARIANT dbv; TCHAR szTemp[MAX_PATH]; szTemp[0] = 0; if ( !DBGetContactSettingTString( NULL, "SRFile", "RecvFilesDirAdv", &dbv )) { if ( lstrlen( dbv.ptszVal ) > 0 ) lstrcpyn( szTemp, dbv.ptszVal, SIZEOF( szTemp )); DBFreeVariant(&dbv); } if ( !szTemp[0] ) #ifdef _UNICODE mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s"), TranslateT("My Received Files")); #else mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s"), "My Received Files"); #endif patchDir( szTemp, SIZEOF(szTemp)); RemoveInvalidPathChars(szTemp); lstrcpyn( szDir, szTemp, cchDir ); } INT_PTR CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { struct FileDlgData *dat; dat=(struct FileDlgData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: { TCHAR *contactName; TCHAR szPath[450]; CLISTEVENT* cle = (CLISTEVENT*)lParam; TranslateDialogDefault(hwndDlg); dat=(struct FileDlgData*)mir_calloc(sizeof(struct FileDlgData)); SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat); dat->hContact = cle->hContact; dat->hDbEvent = cle->hDbEvent; dat->hPreshutdownEvent = HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN); dat->dwTicks = GetTickCount(); EnumChildWindows(hwndDlg,ClipSiblingsChildEnumProc,0); Window_SetIcon_IcoLib(hwndDlg, SKINICON_EVENT_FILE); Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact Permanently to List")); Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View User's Details")); Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View User's History")); Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User Menu")); contactName = cli.pfnGetContactDisplayName( dat->hContact, 0 ); SetDlgItemText(hwndDlg,IDC_FROM,contactName); GetContactReceivedFilesDir(dat->hContact,szPath,SIZEOF(szPath),TRUE); SetDlgItemText(hwndDlg,IDC_FILEDIR,szPath); { int i; char idstr[32]; DBVARIANT dbv; if (shAutoComplete) shAutoComplete(GetWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),GW_CHILD),1); for(i=0;ihContact,(LPARAM)dat->hDbEvent); { DBEVENTINFO dbei={0}; TCHAR datetimestr[64]; char buf[540]; dbei.cbSize=sizeof(dbei); dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)dat->hDbEvent,0); dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob); CallService(MS_DB_EVENT_GET,(WPARAM)dat->hDbEvent,(LPARAM)&dbei); dat->fs = cle->lParam ? (HANDLE)cle->lParam : (HANDLE)*(PDWORD)dbei.pBlob; lstrcpynA(buf, (char*)dbei.pBlob+4, min(dbei.cbBlob+1,SIZEOF(buf))); TCHAR* ptszFileName = DbGetEventStringT( &dbei, buf ); SetDlgItemText(hwndDlg,IDC_FILENAMES,ptszFileName); mir_free(ptszFileName); lstrcpynA(buf, (char*)dbei.pBlob+4+strlen((char*)dbei.pBlob+4)+1, min((int)(dbei.cbBlob-4-strlen((char*)dbei.pBlob+4)),SIZEOF(buf))); TCHAR* ptszDescription = DbGetEventStringT( &dbei, buf ); SetDlgItemText(hwndDlg,IDC_MSG,ptszDescription); mir_free(ptszDescription); mir_free(dbei.pBlob); tmi.printTimeStamp(NULL, dbei.timestamp, _T("t d"), datetimestr, SIZEOF(datetimestr), 0); SetDlgItemText(hwndDlg, IDC_DATE, datetimestr); } { char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0); if (szProto) { CONTACTINFO ci; int hasName = 0; char buf[128]; ZeroMemory(&ci,sizeof(ci)); ci.cbSize = sizeof(ci); ci.hContact = dat->hContact; ci.szProto = szProto; ci.dwFlag = CNF_UNIQUEID; if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) { switch(ci.type) { case CNFT_ASCIIZ: hasName = 1; mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal); mir_free(ci.pszVal); break; case CNFT_DWORD: hasName = 1; mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal); break; } } if (hasName) SetDlgItemTextA(hwndDlg, IDC_NAME, buf ); else SetDlgItemText(hwndDlg, IDC_NAME, contactName); } } if(DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) { RECT rcBtn1,rcBtn2,rcDateCtrl; GetWindowRect(GetDlgItem(hwndDlg,IDC_ADD),&rcBtn1); GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rcBtn2); GetWindowRect(GetDlgItem(hwndDlg,IDC_DATE),&rcDateCtrl); SetWindowPos(GetDlgItem(hwndDlg,IDC_DATE),0,0,0,rcDateCtrl.right-rcDateCtrl.left-(rcBtn2.left-rcBtn1.left),rcDateCtrl.bottom-rcDateCtrl.top,SWP_NOZORDER|SWP_NOMOVE); } else if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0)) { //don't check auto-min here to fix BUG#647620 PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDOK)); } if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) ShowWindow(GetDlgItem(hwndDlg, IDC_ADD),SW_HIDE); return TRUE; } case WM_MEASUREITEM: return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam); case WM_DRAWITEM: { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam; if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) { char *szProto; szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0); if (szProto) { HICON hIcon; hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0); if (hIcon) { DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL); DestroyIcon(hIcon); } } } } return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam); case WM_COMMAND: if ( CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU), (LPARAM)dat->hContact )) break; switch ( LOWORD( wParam )) { case IDC_FILEDIRBROWSE: { TCHAR szDirName[MAX_PATH],szExistingDirName[MAX_PATH]; GetDlgItemText(hwndDlg,IDC_FILEDIR,szDirName,SIZEOF(szDirName)); GetLowestExistingDirName(szDirName,szExistingDirName,SIZEOF(szExistingDirName)); if(BrowseForFolder(hwndDlg,szExistingDirName)) SetDlgItemText(hwndDlg,IDC_FILEDIR,szExistingDirName); } break; case IDOK: { //most recently used directories TCHAR szRecvDir[MAX_PATH],szDefaultRecvDir[MAX_PATH]; GetDlgItemText(hwndDlg,IDC_FILEDIR,szRecvDir,SIZEOF(szRecvDir)); RemoveInvalidPathChars(szRecvDir); GetContactReceivedFilesDir(NULL,szDefaultRecvDir,SIZEOF(szDefaultRecvDir),TRUE); if(_tcsnicmp(szRecvDir,szDefaultRecvDir,lstrlen(szDefaultRecvDir))) { char idstr[32]; int i; DBVARIANT dbv; for(i=MAX_MRU_DIRS-2;i>=0;i--) { mir_snprintf(idstr, SIZEOF(idstr), "MruDir%d",i); if(DBGetContactSettingTString(NULL,"SRFile",idstr,&dbv)) continue; mir_snprintf(idstr, SIZEOF(idstr), "MruDir%d",i+1); DBWriteContactSettingTString(NULL,"SRFile",idstr,dbv.ptszVal); DBFreeVariant(&dbv); } DBWriteContactSettingTString(NULL,"SRFile",idstr,szRecvDir); } } EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAMES),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIRBROWSE),FALSE); GetDlgItemText(hwndDlg,IDC_FILEDIR,dat->szSavePath,SIZEOF(dat->szSavePath)); GetDlgItemText(hwndDlg,IDC_FILE,dat->szFilenames,SIZEOF(dat->szFilenames)); GetDlgItemText(hwndDlg,IDC_MSG,dat->szMsg,SIZEOF(dat->szMsg)); dat->hwndTransfer = FtMgr_AddTransfer(dat); SetWindowLongPtr( hwndDlg, GWLP_USERDATA, 0); //check for auto-minimize here to fix BUG#647620 if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) && DBGetContactSettingByte(NULL,"SRFile","AutoMin",0)) { ShowWindow(hwndDlg,SW_HIDE); ShowWindow(hwndDlg,SW_SHOWMINNOACTIVE); } DestroyWindow(hwndDlg); break; case IDCANCEL: if (dat->fs) CallContactService(dat->hContact,PSS_FILEDENYT,(WPARAM)dat->fs,(LPARAM)TranslateT("Cancelled")); dat->fs=NULL; /* the protocol will free the handle */ DestroyWindow(hwndDlg); break; case IDC_ADD: { ADDCONTACTSTRUCT acs={0}; acs.handle=dat->hContact; acs.handleType=HANDLE_CONTACT; acs.szProto=""; CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs); if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) ShowWindow(GetDlgItem(hwndDlg,IDC_ADD), SW_HIDE); } break; case IDC_USERMENU: { RECT rc; HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0); GetWindowRect((HWND)lParam,&rc); TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL); DestroyMenu(hMenu); } break; case IDC_DETAILS: CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0); break; case IDC_HISTORY: CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0); break; } break; case WM_DESTROY: Window_FreeIcon_IcoLib(hwndDlg); Button_FreeIcon_IcoLib(hwndDlg,IDC_ADD); Button_FreeIcon_IcoLib(hwndDlg,IDC_DETAILS); Button_FreeIcon_IcoLib(hwndDlg,IDC_HISTORY); Button_FreeIcon_IcoLib(hwndDlg,IDC_USERMENU); if ( dat ) FreeFileDlgData( dat ); break; } return FALSE; }