mirror of https://github.com/roytam1/kmeleon.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1587 lines
49 KiB
1587 lines
49 KiB
/* |
|
* Copyright (C) 2000 Brian Harris, Mark Liffiton |
|
* |
|
* 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, 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. |
|
*/ |
|
|
|
#ifdef __MINGW32__ |
|
# define _WIN32_IE 0x0500 |
|
# include <windows.h> |
|
# include <commctrl.h> |
|
# include "../missing.h" |
|
#endif |
|
|
|
#include "stdafx.h" |
|
#include "resource.h" |
|
#include "wininet.h" // for INTERNET_MAX_URL_LENGTH |
|
#include <stdio.h> |
|
#include <io.h> |
|
#include <tchar.h> |
|
#include "utf.h" |
|
#include "LocalesUtils.h" |
|
#include "defines.h" |
|
|
|
#define KMELEON_PLUGIN_EXPORTS |
|
#include "kmeleon_plugin.h" |
|
#include "../../app/KMeleonConst.h" |
|
#include "Utils.h" |
|
#include "DialogUtils.h" |
|
#include "../rebar_menu/hot_tracking.h" |
|
#define WM_DEFERHOTTRACK WM_USER+11 |
|
|
|
#include "BookmarkNode.h" |
|
|
|
#include "ns_bookmarks_functions.h" |
|
|
|
extern WNDPROC KMeleonWndProc; |
|
extern BOOL bChevronEnabled; |
|
char szContentType[BOOKMARKS_TITLE_LEN]; |
|
BOOL gLoaded = FALSE; |
|
|
|
UINT GetSiteIcon(CBookmarkNode *node) |
|
{ |
|
if (node->iconurl.length()) { |
|
UINT idx = kPlugin.kFuncs->GetIconIdx(node->iconurl.c_str()); |
|
if (idx>0) return idx; |
|
} |
|
|
|
char* url = (char*)node->url.c_str(); |
|
char* begin = strstr(url, "://"); |
|
if (!begin) return 0; |
|
char* end = strchr(begin+3, '/'); |
|
if (end) *end = 0; |
|
UINT i = kPlugin.kFuncs->GetIconIdx(url); |
|
if (end) *end = '/'; |
|
return i; |
|
} |
|
|
|
void InitImageList(HIMAGELIST& imageList) |
|
{ |
|
if (imageList) |
|
ImageList_Destroy(imageList); |
|
|
|
HBITMAP bitmap; |
|
int ilc_bits = ILC_COLOR; |
|
COLORREF bgCol = RGB(255, 0, 255); |
|
|
|
wchar_t szFullPath[MAX_PATH]; |
|
kPlugin.kFuncs->FindSkinFile(L"bookmarks.bmp", szFullPath, MAX_PATH); |
|
FILE *fp = _tfopen(szFullPath, _T("r")); |
|
if (fp) { |
|
fclose(fp); |
|
bitmap = (HBITMAP)LoadImage(NULL, szFullPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); |
|
} else { |
|
bitmap = LoadBitmap(kPlugin.hDllInstance, MAKEINTRESOURCE(IDB_IMAGES)); |
|
bgCol = RGB(192, 192, 192); |
|
} |
|
|
|
BITMAP bmp; |
|
GetObject(bitmap, sizeof(BITMAP), &bmp); |
|
|
|
ilc_bits = (bmp.bmBitsPixel == 32 ? ILC_COLOR32 : (bmp.bmBitsPixel == 24 ? ILC_COLOR24 : (bmp.bmBitsPixel == 16 ? ILC_COLOR16 : (bmp.bmBitsPixel == 8 ? ILC_COLOR8 : (bmp.bmBitsPixel == 4 ? ILC_COLOR4 : ILC_COLOR))))); |
|
imageList = ImageList_Create(bmp.bmWidth/6, bmp.bmHeight, ILC_MASK | ilc_bits, 4, 4); |
|
if (imageList && bitmap) |
|
ImageList_AddMasked(imageList, bitmap, bgCol); |
|
if (bitmap) |
|
DeleteObject(bitmap); |
|
} |
|
|
|
// Preferences Dialog function |
|
BOOL CALLBACK DlgProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { |
|
switch (uMsg) { |
|
case WM_INITDIALOG: |
|
SendDlgItemMessage(hWnd, IDC_REBARENABLED, BM_SETCHECK, gToolbarEnabled, 0); |
|
SetDlgItemText(hWnd, IDC_BOOKMARKS_FILE, gBookmarkFile); |
|
SetDlgItemInt(hWnd, IDC_MAX_MENU_LENGTH, gMaxMenuLength, false); |
|
SendDlgItemMessage(hWnd, IDC_MENU_AUTODETECT, BM_SETCHECK, gMenuAutoDetect, 0); |
|
if (gMenuAutoDetect) { |
|
EnableWindow(GetDlgItem(hWnd, IDC_MAX_MENU_LENGTH), false); |
|
} |
|
SetDlgItemInt(hWnd, IDC_MAX_TB_SIZE, gMaxTBSize, false); |
|
break; |
|
case WM_COMMAND: |
|
switch(HIWORD(wParam)) { |
|
case BN_CLICKED: |
|
switch (LOWORD(wParam)) { |
|
case IDC_MENU_AUTODETECT: |
|
if (SendDlgItemMessage(hWnd, IDC_MENU_AUTODETECT, BM_GETCHECK, 0, 0)) { |
|
EnableWindow(GetDlgItem(hWnd, IDC_MAX_MENU_LENGTH), false); |
|
} |
|
else { |
|
EnableWindow(GetDlgItem(hWnd, IDC_MAX_MENU_LENGTH), true); |
|
} |
|
break; |
|
case IDC_BROWSE: |
|
{ |
|
TCHAR tempPath[MAX_PATH]; |
|
HWND hBookmarksFileWnd = GetDlgItem(hWnd, IDC_BOOKMARKS_FILE); |
|
|
|
GetWindowText(hBookmarksFileWnd, tempPath, MAX_PATH); |
|
if (BrowseForBookmarks(tempPath)) { |
|
// if the file they chose doesn't exist, create it |
|
FILE *bmFile = _tfopen(gBookmarkFile, _T("r")); |
|
if (!bmFile) { |
|
bmFile = _tfopen(gBookmarkFile, _T("w")); |
|
gGeneratedByUs = true; |
|
} |
|
fclose(bmFile); |
|
|
|
SetWindowText(hBookmarksFileWnd, tempPath); |
|
SetFocus(hBookmarksFileWnd); |
|
} |
|
} |
|
break; |
|
case IDOK: { |
|
gToolbarEnabled = SendDlgItemMessage(hWnd, IDC_REBARENABLED, BM_GETCHECK, 0, 0); |
|
kPlugin.kFuncs->SetPreference(PREF_BOOL, PREFERENCE_TOOLBAR_ENABLED, &gToolbarEnabled, FALSE); |
|
|
|
TCHAR tempPath[MAX_PATH]; |
|
GetDlgItemText(hWnd, IDC_BOOKMARKS_FILE, tempPath, MAX_PATH); |
|
if (_tcsicmp(tempPath, gBookmarkFile) != 0) { |
|
GetDlgItemText(hWnd, IDC_BOOKMARKS_FILE, gBookmarkFile, MAX_PATH); |
|
kPlugin.kFuncs->SetPreference(PREF_TSTRING, PREFERENCE_BOOKMARK_FILE, gBookmarkFile, false); |
|
gBookmarkDefFile = false; |
|
delete gBookmarkRoot->child; |
|
delete gBookmarkRoot->next; |
|
gBookmarkRoot->child = NULL; |
|
gBookmarkRoot->next = NULL; |
|
FILE *bmFile = _tfopen(gBookmarkFile, _T("a")); |
|
if (bmFile) |
|
fclose(bmFile); |
|
else { |
|
MessageBox(NULL, gLoc->GetString(IDS_CREATING_NEW), _T(PLUGIN_NAME), 0); |
|
bmFile = _tfopen(gBookmarkFile, _T("w")); |
|
if (bmFile) { |
|
fclose(bmFile); |
|
gGeneratedByUs = true; |
|
} |
|
|
|
} |
|
LoadBM(gBookmarkFile); |
|
} |
|
gMaxMenuLength = GetDlgItemInt(hWnd, IDC_MAX_MENU_LENGTH, NULL, false); |
|
if (gMaxMenuLength < 1) gMaxMenuLength = 20; |
|
kPlugin.kFuncs->SetPreference(PREF_INT, PREFERENCE_MAX_MENU_LENGTH, &gMaxMenuLength, FALSE); |
|
|
|
gMenuAutoDetect = SendDlgItemMessage(hWnd, IDC_MENU_AUTODETECT, BM_GETCHECK, 0, 0); |
|
kPlugin.kFuncs->SetPreference(PREF_BOOL, PREFERENCE_MENU_AUTODETECT, &gMenuAutoDetect, FALSE); |
|
|
|
gMaxTBSize = GetDlgItemInt(hWnd, IDC_MAX_TB_SIZE, NULL, false); |
|
if (gMaxTBSize < 1) gMaxTBSize = 20; |
|
kPlugin.kFuncs->SetPreference(PREF_INT, PREFERENCE_MAX_TB_SIZE, &gMaxTBSize, FALSE); |
|
|
|
// rebuild menu and toolbars to provide instant gratification to users |
|
Rebuild(); |
|
} |
|
// fall through... |
|
case IDCANCEL: |
|
SendMessage(hWnd, WM_CLOSE, 0, 0); |
|
} |
|
} |
|
break; |
|
case WM_CLOSE: |
|
EndDialog(hWnd, (INT_PTR) NULL); |
|
break; |
|
default: |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
BOOL BrowseForBookmarks(TCHAR *file) |
|
{ |
|
OPENFILENAME ofn; |
|
ofn.lStructSize = sizeof(OPENFILENAME); |
|
ofn.hInstance = kPlugin.hDllInstance; |
|
ofn.hwndOwner = NULL; |
|
ofn.lpstrCustomFilter = NULL; |
|
ofn.nMaxCustFilter = 0; |
|
ofn.nFilterIndex = 1; |
|
ofn.lpstrFileTitle = NULL; |
|
ofn.nMaxFileTitle = MAX_PATH; |
|
ofn.lpstrInitialDir = NULL; |
|
ofn.nFileOffset = 0; |
|
ofn.nFileExtension = 0; |
|
ofn.lpstrDefExt = NULL; |
|
ofn.lCustData = 0; |
|
ofn.lpfnHook = NULL; |
|
ofn.lpTemplateName = NULL; |
|
TCHAR* filter = _tcsdup(gLoc->GetString(IDS_FILTER)); |
|
for (TCHAR* p = filter;*p;p++) |
|
if (*p == '|') *p=0; |
|
ofn.lpstrFilter = filter; |
|
ofn.lpstrFile = file; |
|
ofn.nMaxFile = MAX_PATH; |
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_LONGNAMES | OFN_EXPLORER | OFN_HIDEREADONLY; |
|
ofn.lpstrTitle = _T(PLUGIN_NAME); |
|
|
|
if (GetOpenFileName(&ofn)) { |
|
free(filter); |
|
return true; |
|
} |
|
else { |
|
free(filter); |
|
return false; |
|
} |
|
} |
|
|
|
|
|
int GlobalReplace(char *str, char *a, char *b) { |
|
char *prev, *p, *q; |
|
int i = 0; |
|
|
|
p = q = prev = strdup(str); |
|
*str = 0; |
|
|
|
while (p && *p && (p = strstr(p, a)) != NULL) { |
|
i++; |
|
*p = 0; |
|
strcat(str, q); |
|
strcat(str, b); |
|
p += strlen(a); |
|
q = p; |
|
} |
|
|
|
if (q && *q) |
|
strcat(str, q); |
|
free(prev); |
|
|
|
return i; |
|
} |
|
|
|
char *EncodeQuotes(const char *str) { |
|
char *pszStr = (char *)malloc(strlen(str)*3+1); |
|
if (pszStr) { |
|
strcpy(pszStr, str); |
|
GlobalReplace(pszStr, "\"", "%22"); |
|
} |
|
return pszStr; |
|
} |
|
|
|
char *EncodeString(const char *str) { |
|
char *pszStr = (char *)malloc(strlen(str)*6+1); |
|
if (pszStr) { |
|
strcpy(pszStr, str); |
|
GlobalReplace(pszStr, "&", "&"); |
|
GlobalReplace(pszStr, "<", "<"); |
|
GlobalReplace(pszStr, ">", ">"); |
|
GlobalReplace(pszStr, "\"", """); |
|
GlobalReplace(pszStr, "\'", "'"); |
|
} |
|
return pszStr; |
|
} |
|
|
|
char *DecodeQuotes(const char *str) { |
|
char *pszStr = (char *)malloc(strlen(str) + INTERNET_MAX_URL_LENGTH); |
|
if (pszStr) { |
|
strcpy(pszStr, str); |
|
GlobalReplace(pszStr, "%22", "\""); |
|
} |
|
return pszStr; |
|
} |
|
|
|
char *DecodeString(const char *str) { |
|
if (!str) return nullptr; |
|
char *pszStr = (char *)malloc(strlen(str) + INTERNET_MAX_URL_LENGTH); |
|
if (pszStr) { |
|
strcpy(pszStr, str); |
|
GlobalReplace(pszStr, "&", "&"); |
|
GlobalReplace(pszStr, "<", "<"); |
|
GlobalReplace(pszStr, ">", ">"); |
|
GlobalReplace(pszStr, """, "\""); |
|
GlobalReplace(pszStr, "'", "\'"); |
|
} |
|
return pszStr; |
|
} |
|
|
|
|
|
// Save bookmarks |
|
static void SaveBookmarks(FILE *bmFile, CBookmarkNode *node) |
|
{ |
|
#define MAXSPACER 50 |
|
int type; |
|
CBookmarkNode *child; |
|
static char szSpacer[MAXSPACER+1] = {0}; |
|
|
|
fprintf(bmFile, "%s<DL><p>\n", szSpacer); |
|
if (strlen(szSpacer) < MAXSPACER) szSpacer[strlen(szSpacer)] = ' '; // add a space |
|
|
|
for (child=node->child; child; child=child->next) { |
|
type = child->type; |
|
if (type == BOOKMARK_FOLDER){ |
|
char *psz, *psz2; |
|
char szFolderFlags[1024] = {0}; |
|
if (child->flags & BOOKMARK_FLAG_GRP) |
|
strcat(szFolderFlags, "FOLDER_GROUP=\"true\" "); |
|
if (child->nick.c_str() && *(child->nick.c_str())) { |
|
strcat(szFolderFlags, "SHORTCUTURL=\""); |
|
strcat(szFolderFlags, child->nick.c_str()); |
|
strcat(szFolderFlags, "\" "); |
|
} |
|
if (child->m_id.length()) { |
|
strcat(szFolderFlags, "ID=\""); |
|
strcat(szFolderFlags, child->m_id.c_str()); |
|
strcat(szFolderFlags, "\" "); |
|
} |
|
|
|
if (child->flags & BOOKMARK_FLAG_TB) |
|
strcat(szFolderFlags, "PERSONAL_TOOLBAR_FOLDER=\"true\" "); //ID=\"NC:PersonalToolbarFolder\" "); |
|
if (child->flags & BOOKMARK_FLAG_NB) |
|
strcat(szFolderFlags, "NEWITEMHEADER "); |
|
if (child->flags & BOOKMARK_FLAG_BM) |
|
strcat(szFolderFlags, "MENUHEADER "); |
|
psz = EncodeString(child->text.c_str()); |
|
fprintf(bmFile, "%s<DT><H3 %sADD_DATE=\"%ld\">", szSpacer, szFolderFlags, child->addDate); |
|
fprintf(bmFile, "%s</H3>\n", psz); |
|
if (psz) free(psz); |
|
|
|
if (child->desc.c_str() != NULL && *(child->desc.c_str()) != 0) { |
|
psz = EncodeString(child->desc.c_str()); |
|
fprintf(bmFile, "%s<DD>%s\n", szSpacer, psz ? psz : ""); |
|
if (psz) free(psz); |
|
} |
|
|
|
if (strlen(szSpacer) < MAXSPACER) szSpacer[strlen(szSpacer)] = ' '; // add a space |
|
SaveBookmarks(bmFile, child); |
|
szSpacer[strlen(szSpacer)-1] = 0; // remove the space |
|
} |
|
else if (type == BOOKMARK_SEPARATOR) { |
|
fprintf(bmFile, "%s<HR>\n", szSpacer); |
|
} |
|
else if (type == BOOKMARK_BOOKMARK) { |
|
char *psz; |
|
|
|
fprintf(bmFile, "%s<DT><A", szSpacer); |
|
psz = EncodeQuotes(child->url.c_str()); |
|
fprintf(bmFile, " HREF=\"%s\"", psz ? psz : ""); |
|
if (psz) free(psz); |
|
|
|
fprintf(bmFile, " ADD_DATE=\"%ld\"", child->addDate); |
|
fprintf(bmFile, " LAST_VISIT=\"%ld\"", child->lastVisit); |
|
fprintf(bmFile, " LAST_MODIFIED=\"%ld\"", child->lastModified); |
|
if (child->m_id.length()) |
|
fprintf(bmFile, " ID=\"%s\"", child->m_id.c_str()); |
|
if (child->icon.length()) |
|
fprintf(bmFile, " ICON=\"%s\"", child->icon.c_str()); |
|
if (child->iconurl.length()) |
|
fprintf(bmFile, " ICONURL=\"%s\"", child->iconurl.c_str()); |
|
if (child->feedurl.length()) |
|
fprintf(bmFile, " FEEDURL=\"%s\"", child->feedurl.c_str()); |
|
psz = (char *) child->nick.c_str(); |
|
if (psz && *psz) { |
|
fprintf(bmFile, " SHORTCUTURL=\"%s\"", psz); |
|
|
|
} |
|
psz = (char *) child->charset.c_str(); |
|
if (psz && *psz) |
|
fprintf(bmFile, " LAST_CHARSET=\"%s\"", psz); |
|
psz = EncodeString(child->text.c_str()); |
|
fprintf(bmFile, ">%s</A>\n", psz ? psz : ""); |
|
if (psz) free(psz); |
|
|
|
if (child->desc.c_str() != NULL && *(child->desc.c_str()) != 0) { |
|
psz = EncodeString(child->desc.c_str()); |
|
fprintf(bmFile, "%s<DD>%s\n", szSpacer, psz ? psz : ""); |
|
if (psz) free(psz); |
|
} |
|
} |
|
// if it falls through, there's a problem, but we'll just ignore it for now. |
|
} |
|
szSpacer[strlen(szSpacer)-1] = 0; // remove the space |
|
fprintf(bmFile, "%s</DL><p>\n", szSpacer); |
|
} |
|
|
|
#include <sys/stat.h> |
|
static void create_backup(const TCHAR *file, int num=2) |
|
{ |
|
static BOOL bBackedUp = 0; |
|
|
|
if (bBackedUp) |
|
return; |
|
|
|
TCHAR buf[MAX_PATH]; |
|
_tcscpy(buf, file); |
|
TCHAR* dot = _tcsrchr(buf, '.'); |
|
if (dot) |
|
_tcscpy(dot, _T("_backup.html")); |
|
else |
|
_tcscat(buf, _T("_backup")); |
|
|
|
struct _stat s = {0}; |
|
if (_tstat(buf, &s)!=-1 && s.st_mtime > time(NULL) - 172800) |
|
return; |
|
|
|
_tunlink(buf); |
|
_trename(file, buf); |
|
|
|
bBackedUp = 1; |
|
} |
|
|
|
void SaveBM(const TCHAR *file) |
|
{ |
|
if (!gLoaded) |
|
return; |
|
|
|
if (!gBookmarkRoot->child && !gBookmarkRoot->next) { |
|
if (MessageBox(NULL, _T("The bookmarks tree is empty.\nDo you really want to erase all your bookmarks?"), _T(PLUGIN_NAME) _T(": WARNING") , MB_YESNO|MB_ICONEXCLAMATION) != IDYES) { |
|
LoadBM(gBookmarkFile); |
|
if (!gBookmarkRoot->child && !gBookmarkRoot->next) { |
|
MessageBox(NULL, _T("Unable to recover old bookmarks."), _T(PLUGIN_NAME) _T(": BUG WARNING") , MB_OK|MB_ICONSTOP); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
BOOL warn = TRUE; |
|
kPlugin.kFuncs->GetPreference(PREF_BOOL, "kmeleon.bookmarks.warnOnSave", &warn, &warn); |
|
if (!gGeneratedByUs && warn) { |
|
if (MessageBox(NULL, gLoc->GetString(IDS_NOT_BY_US), _T(PLUGIN_NAME), MB_YESNO) != IDYES) { |
|
return; |
|
} |
|
} |
|
|
|
DWORD dwWaitResult; |
|
dwWaitResult = WaitForSingleObject( ghMutex, 1000L); |
|
if (dwWaitResult == WAIT_TIMEOUT) { |
|
MessageBox(NULL, _T("Unable to get MutEx for bookmarks file.\\nFile not saved."), _T(PLUGIN_NAME) _T(": WARNING") , MB_OK|MB_ICONSTOP); |
|
return; |
|
} |
|
|
|
TCHAR buf[MAX_PATH]; |
|
_tcscpy(buf, file); |
|
TCHAR *p, *q; |
|
p = _tcsrchr(buf, _T('/')); |
|
q = _tcsrchr(buf, _T('\\')); |
|
if (!q || p>q) q = p; |
|
p = _tcsrchr(buf, _T('.')); |
|
if (!p || q>p) |
|
_tcscat(buf, _T("XXXXXX")); |
|
else if (p) |
|
_tcscat(p, _T("XXXXXX")); |
|
else |
|
_tcscat(buf, _T("XXXXXX")); |
|
p = _tmktemp(buf); |
|
|
|
FILE *bmFile = _tfopen(buf, _T("w")); |
|
if (bmFile){ |
|
fprintf(bmFile, "%s\n", BOOKMARK_TAG); |
|
fprintf(bmFile, "%s\n", KMELEON_TAG); |
|
fprintf(bmFile, "%s\n", COMMENT_TAG); |
|
// FIXME - figure out if this needs to be here, or if it should be different on non-US-English systems |
|
// fprintf(bmFile, "%s\n", CONTENT_TYPE_TAG); |
|
if (*szContentType) |
|
fprintf(bmFile, "%s%s>\n", CONTENT_TYPE_TAG, szContentType); |
|
fprintf(bmFile, "<TITLE>%s</TITLE>\n", gBookmarksTitle); |
|
fprintf(bmFile, "<H1>%s</H1>\n\n", gBookmarksTitle); |
|
|
|
SaveBookmarks(bmFile, gBookmarkRoot); |
|
|
|
if (fclose(bmFile) == EOF) { |
|
_tunlink(buf); |
|
MessageBox(NULL, gLoc->GetString(IDS_FAILED_SAVE), gLoc->GetString(IDS_ERROR), MB_OK|MB_ICONERROR); |
|
ReleaseMutex(ghMutex); |
|
return; |
|
} |
|
|
|
create_backup(file); |
|
|
|
_tunlink(file); |
|
if (_trename(buf, file) != 0) { |
|
MessageBox(NULL, gLoc->GetString(IDS_FAILED_SAVE), gLoc->GetString(IDS_ERROR), MB_OK|MB_ICONERROR); |
|
ReleaseMutex(ghMutex); |
|
return; |
|
} |
|
} |
|
|
|
gGeneratedByUs = true; |
|
gBookmarksModified = false; |
|
|
|
/* this is to support both NS 4 and NS 6 style bookmarks */ |
|
kPlugin.kFuncs->SetPreference(PREF_STRING, PREFERENCE_TOOLBAR_FOLDER, (void*)gBookmarkRoot->FindSpecialNode(BOOKMARK_FLAG_TB)->text.c_str(), false); |
|
|
|
ReleaseMutex(ghMutex); |
|
} |
|
|
|
|
|
// Load bookmarks |
|
void ParseBookmarks(char *bmFileBuffer, CBookmarkNode &node) |
|
{ |
|
char *p; |
|
char *t; |
|
bool found_tb = false; |
|
CBookmarkNode * lastNode = &node; |
|
|
|
while ((p = strtok(NULL, "\n")) != NULL){ |
|
if ((t = strstr(p, "<DT><H3")) != NULL){ |
|
t+=7; |
|
char *_name = strchr(t, '>'); |
|
if (_name) { |
|
*_name = 0; _name++; |
|
} |
|
else { |
|
_name = ""; |
|
} |
|
|
|
char *end = strrchr(_name, '<'); |
|
if (end) *end = 0; |
|
|
|
time_t addDate=0; |
|
char *id = NULL; |
|
|
|
char *d; |
|
d = strstr(t, "ADD_DATE=\""); |
|
if (d) { |
|
d+=10; |
|
addDate = atol(d); |
|
} |
|
|
|
char *nick = NULL; |
|
d = strstr(t, "SHORTCUTURL=\""); |
|
if (d) { |
|
d+=13; |
|
|
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
nick = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
|
|
d = strstr(t, "ID=\""); |
|
if (d) { |
|
d+=4; |
|
|
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
id = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
|
|
char* name = DecodeString(_name ? _name : ""); |
|
|
|
CBookmarkNode * newNode = new CBookmarkNode(0, name, "", nick, "", "", BOOKMARK_FOLDER, addDate, 0, 0, id); |
|
node.AddChild(newNode); |
|
|
|
if (nick) free(nick); |
|
if (id) free(id); |
|
lastNode = newNode; |
|
|
|
ParseBookmarks(end, *newNode); |
|
|
|
// this is to support both NS 4 and NS 6 style bookmarks |
|
// FIXME - We should only allow one toolbar folder, eh? |
|
// Example: Two folders, same name, set first one as toolbar folder. |
|
// Pref saved w/ name only, though only one gets PERSONAL_TOOL... |
|
// Both given FLAG_TB when next parsed, because both match gToolbarFolder |
|
// Note: NS 4 has a bug (tee-hee!) - It just sets the first that matches to the toolbar. |
|
// So I'll just do the same for now. First folder that matches gets it, no others. |
|
// But this should still be fixed (probably by just removing NS 4 compatibility...) |
|
if ( !found_tb && |
|
((strcmp(name, gToolbarFolder) == 0) || |
|
(strstr(t, _Q(PERSONAL_TOOLBAR_FOLDER="true")))) ) |
|
{ |
|
newNode->flags |= BOOKMARK_FLAG_TB; |
|
found_tb = true; |
|
} |
|
|
|
if (name) free(name); |
|
|
|
if ( strstr(t, _Q(FOLDER_GROUP="true")) ) |
|
{ |
|
newNode->flags |= BOOKMARK_FLAG_GRP; |
|
} |
|
|
|
// These are both NS 4 style - I don't know how Mozilla does it |
|
if ( strstr(t, "NEWITEMHEADER") ) { |
|
newNode->flags |= BOOKMARK_FLAG_NB; |
|
} |
|
if ( strstr(t, "MENUHEADER") ) { |
|
newNode->flags |= BOOKMARK_FLAG_BM; |
|
} |
|
|
|
newNode->id = 0; // later, in buildmenu, this will be set to the hmenu |
|
} |
|
else if ((t = strstr(p, "<DT><A HREF=\"")) != NULL) { |
|
t+=13; // t now points to the url |
|
|
|
char *name = t; |
|
char *url = t; |
|
|
|
// if there's a quote, chop it |
|
char *q = strchr(url, '\"'); |
|
if (q) { |
|
*q = 0; |
|
t = q+1; |
|
} |
|
|
|
time_t addDate=0; |
|
time_t lastVisit=0; |
|
time_t lastModified=0; |
|
char *nick = NULL; |
|
char *charset = NULL; |
|
char *id = NULL; |
|
char *icon = NULL; |
|
char *iconurl = NULL; |
|
char *feedurl = NULL; |
|
|
|
char *d; |
|
d = strstr(t, "ID=\""); |
|
if (d) { |
|
d+=4; |
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
id = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
d = strstr(t, "ADD_DATE=\""); |
|
if (d) { |
|
d+=10; |
|
addDate = atol(d); |
|
} |
|
d = strstr(t, "LAST_VISIT=\""); |
|
if (d) { |
|
d+=12; |
|
lastVisit = atol(d); |
|
} |
|
d = strstr(t, "LAST_MODIFIED=\""); |
|
if (d) { |
|
d+=15; |
|
lastModified = atol(d); |
|
} |
|
d = strstr(t, "SHORTCUTURL=\""); |
|
if (d) { |
|
d+=13; |
|
|
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
nick = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
d = strstr(t, "ICON=\""); |
|
if (d) { |
|
d+=6; |
|
|
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
icon = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
d = strstr(t, "ICONURL=\""); |
|
if (d) { |
|
d+=9; |
|
|
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
iconurl = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
|
|
d = strstr(t, "FEEDURL=\""); |
|
if (d) { |
|
d+=9; |
|
|
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
feedurl = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
d = strstr(t, "LAST_CHARSET=\""); |
|
if (d) { |
|
d+=14; |
|
|
|
char *q = strchr(d, '\"'); |
|
if (q) { |
|
*q = 0; |
|
charset = strdup(d); |
|
*q = '\"'; |
|
} |
|
} |
|
|
|
t = strchr(t, '>'); |
|
if (t) { |
|
name = t+1; |
|
q = strchr(name, '<'); |
|
if (q) { |
|
*q = 0; |
|
} |
|
} |
|
else { |
|
name = ""; |
|
} |
|
|
|
// if we have no name, set our name to the url |
|
//if (name[0] == 0) |
|
// name = url; |
|
|
|
char *pszTxt, *pszUrl; |
|
pszUrl = DecodeQuotes(url ? url : ""); |
|
pszTxt = DecodeString(name ? name : ""); |
|
|
|
lastNode = new CBookmarkNode(kPlugin.kFuncs->GetCommandIDs(1), pszTxt, pszUrl, nick, NULL, charset, BOOKMARK_BOOKMARK, addDate, lastVisit, lastModified, id, feedurl, icon, iconurl); |
|
node.AddChild(lastNode); |
|
if (pszUrl) free(pszUrl); |
|
if (pszTxt) free(pszTxt); |
|
if (id) free(id); |
|
if (nick) free(nick); |
|
if (charset) free(charset); |
|
if (feedurl) free(feedurl); |
|
if (icon) free(icon); |
|
if (iconurl) free(iconurl); |
|
} |
|
else if ((t = strstr(p, "</DL>")) != NULL) { |
|
return; |
|
} |
|
else if ((t = strstr(p, "<HR>")) != NULL) { |
|
lastNode = new CBookmarkNode(0, "", "", "", "", "", BOOKMARK_SEPARATOR); |
|
node.AddChild(lastNode); |
|
} |
|
else if ((t = strstr(p, "<TITLE>")) != NULL) { |
|
t+=7; // t now points to the title |
|
|
|
char *end = strrchr(t, '<'); |
|
if (end) { |
|
if (end > t+BOOKMARKS_TITLE_LEN) end = t+BOOKMARKS_TITLE_LEN; |
|
*end = 0; |
|
} |
|
|
|
strcpy(gBookmarksTitle, t); |
|
} |
|
else if ((t = strstr(p, "<DD>")) != NULL && lastNode != NULL) { |
|
char *e = t+4; |
|
while (*e && *e!='\n') |
|
e++; |
|
*e = 0; |
|
e = strdup(t+4); |
|
if (e && *e) { |
|
char *tmp = DecodeString(e); |
|
free(e); |
|
e = tmp; |
|
} |
|
if (!e || !*e) { |
|
if (e) |
|
free(e); |
|
e = DecodeString(t+4); |
|
} |
|
lastNode->desc = e ? e : ""; |
|
if (e) |
|
free(e); |
|
} |
|
else if (strstr(p, KMELEON_TAG) != NULL) { |
|
gGeneratedByUs = true; |
|
} |
|
else if ((t = strstr(p, CONTENT_TYPE_TAG)) != NULL) { |
|
t += strlen(CONTENT_TYPE_TAG); |
|
strncpy(szContentType, t, sizeof(szContentType)-1); |
|
szContentType[sizeof(szContentType)-1] = 0; |
|
t = strchr(szContentType, '>'); |
|
if (t) |
|
*t = 0; |
|
} |
|
} |
|
return; |
|
} |
|
|
|
void LoadBM(const TCHAR *file) |
|
{ |
|
DWORD dwWaitResult; |
|
dwWaitResult = WaitForSingleObject( ghMutex, 1000L); |
|
if (dwWaitResult == WAIT_TIMEOUT) { |
|
MessageBox(NULL, _T("Unable to get MutEx for bookmarks file.\\nFile not loaded."), _T(PLUGIN_NAME) _T(": WARNING") , MB_OK|MB_ICONSTOP); |
|
return; |
|
} |
|
|
|
FILE *bmFile = _tfopen(file, _T("r")); |
|
if (bmFile){ |
|
long bmFileSize = FileSize(bmFile); |
|
if (bmFileSize) { |
|
char *bmFileBuffer = new char[bmFileSize]; |
|
if (bmFileBuffer){ |
|
size_t s = fread(bmFileBuffer, sizeof(char), bmFileSize, bmFile); |
|
bmFileBuffer[s] = 0; |
|
strtok(bmFileBuffer, "\n"); |
|
ParseBookmarks(bmFileBuffer, *gBookmarkRoot); |
|
gLoaded = TRUE; |
|
delete [] bmFileBuffer; |
|
} |
|
} |
|
fclose(bmFile); |
|
gLoaded = TRUE; |
|
} |
|
|
|
ReleaseMutex(ghMutex); |
|
} |
|
|
|
void findNick(char *nick, char **url) |
|
{ |
|
static char* sUrl = 0; |
|
CBookmarkNode *retNode = (*nick ? gBookmarkRoot->FindNick(nick) : NULL); |
|
if (sUrl) { |
|
free(sUrl); |
|
sUrl = 0; |
|
} |
|
if (retNode) { |
|
if (retNode->type == BOOKMARK_BOOKMARK) { |
|
|
|
*url = (char *) malloc(INTERNET_MAX_URL_LENGTH+1); |
|
strcpy(*url, (char*)retNode->url.c_str()); |
|
} |
|
else if (retNode->type == BOOKMARK_FOLDER) { |
|
CBookmarkNode *c = retNode->child; |
|
int len = 0; |
|
while (c) { |
|
if (c->type == BOOKMARK_BOOKMARK && c->url.c_str()) |
|
len += strlen(c->url.c_str()) + 1; |
|
c = c->next; |
|
} |
|
|
|
if (!len) return; |
|
char *pUrl = (char *)malloc(len+1); |
|
*url = pUrl; |
|
|
|
c = retNode->child; |
|
while (c) { |
|
if (c->type == BOOKMARK_BOOKMARK && c->url.c_str()) { |
|
strcpy(pUrl, c->url.c_str()); |
|
pUrl += strlen(pUrl); |
|
*pUrl++ = '\t'; |
|
} |
|
c = c->next; |
|
} |
|
*pUrl = 0; |
|
} |
|
sUrl = *url; |
|
} |
|
} |
|
|
|
// Build Menu |
|
void BuildMenu(HMENU menu, CBookmarkNode *node, BOOL isContinuation) |
|
{ |
|
// screen height |
|
int cy = GetSystemMetrics(SM_CYSCREEN); |
|
// menu line height |
|
// int cmenu = GetSystemMetrics(SM_CYMENU); |
|
// if bmp_menu is enabled, the menu items will actually be at least 18 pixels... but this system call won't reflect that |
|
// in any case, SM_CYMENU gets the height of the menu bar, not a menu item |
|
// for now we'll just assume bmp_menu is enabled and they're 18 pixels... |
|
int cmenu = max(18,GetSystemMetrics(SM_CYMENU)); |
|
|
|
// space to allow above menu for title bar, menu bar (assuming maximized window), and extra frame junk |
|
#define MENUPADDING 50 |
|
|
|
int maxLength = (gMenuAutoDetect) ? (int)((cy-MENUPADDING)/cmenu) : gMaxMenuLength; |
|
|
|
CBookmarkNode *child; |
|
int count = GetMenuItemCount(menu); |
|
|
|
for (child = (isContinuation) ? node : node->child ; child ; child = child->next , count++) { |
|
if (count == maxLength) { |
|
HMENU childMenu = CreatePopupMenu(); |
|
AppendMenu(menu, MF_STRING|MF_POPUP, (UINT)childMenu, _T("[more]")); |
|
BuildMenu(childMenu, child, true); |
|
break; |
|
} |
|
else if (child->type == BOOKMARK_SEPARATOR) { |
|
AppendMenu(menu, MF_SEPARATOR, 0, _T("")); |
|
} |
|
else if (child->type == BOOKMARK_FOLDER) { |
|
HMENU childMenu = CreatePopupMenu(); |
|
child->id = (UINT)childMenu; // we have to save off the HMENU for the rebar |
|
|
|
#if 1 |
|
// condense the title and escape ampersands |
|
TCHAR *pszTemp = fixString(CUTF8_to_T(child->text.c_str()), 40); |
|
AppendMenu(menu, MF_STRING|MF_POPUP, (UINT)childMenu, pszTemp); |
|
delete pszTemp; |
|
#else |
|
char *szTitle = (char*) child->text.c_str(); |
|
int len = strlen(szTitle)+1; |
|
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0, |
|
szTitle, len, |
|
NULL, 0); |
|
WCHAR *wszTitle = new WCHAR[wlen+1]; |
|
wlen = MultiByteToWideChar(CP_UTF8, 0, |
|
szTitle, len, |
|
wszTitle, wlen); |
|
AppendMenuW(menu, MF_STRING|MF_POPUP, (UINT)childMenu, wszTitle); |
|
|
|
delete wszTitle; |
|
#endif |
|
int pos; |
|
for (pos=0;pos<GetMenuItemCount(menu);pos++) |
|
if (GetSubMenu(menu,pos) == childMenu) |
|
break; |
|
MENUITEMINFO mi = {0}; |
|
mi.cbSize = sizeof(mi); |
|
mi.fMask = MIIM_DATA | MIIM_FTYPE; |
|
mi.fType = MF_OWNERDRAW; |
|
mi.dwItemData = (ULONG_PTR)child->text.c_str(); |
|
int xx = SetMenuItemInfo(menu, pos, TRUE, &mi); |
|
|
|
BuildMenu(childMenu, child, false); |
|
BOOL addBookmark = TRUE; |
|
kPlugin.kFuncs->GetPreference(PREF_BOOL, PREFERENCE_BOOKMARK_MENUADD, &addBookmark, &addBookmark); |
|
if (addBookmark) { |
|
AppendMenu(childMenu, MF_SEPARATOR, 0, _T("")); |
|
AppendMenu(childMenu, MF_STRING, nAddBookmarkHereCommand, gLoc->GetString(IDS_ADD_BOOKMARK_HERE)); |
|
} |
|
} |
|
else if (child->type == BOOKMARK_BOOKMARK) { |
|
// condense the title and escape ampersands |
|
if (!child->text.empty()) // BUG #785 |
|
{ |
|
TCHAR *pszTemp = fixString(CUTF8_to_T(child->text.c_str()), 40); |
|
AppendMenu(menu, MF_STRING, child->id, pszTemp); |
|
MENUITEMINFO mi = {0}; |
|
mi.cbSize = sizeof(mi); |
|
mi.fMask = MIIM_DATA | MIIM_FTYPE; |
|
mi.fType = MF_STRING | MF_OWNERDRAW; |
|
mi.dwItemData = (ULONG_PTR)child->text.c_str(); |
|
SetMenuItemInfo(menu, child->id, FALSE, &mi); |
|
free(pszTemp); |
|
} |
|
|
|
} |
|
} |
|
kPlugin.kFuncs->SetMenuDrawProc(menu, DrawBitmap); |
|
} |
|
|
|
void CopyRebar(HWND hWndNewTB, HWND hWndOldTB) |
|
{ |
|
int i = 0; |
|
TBBUTTON button; |
|
|
|
SetWindowText(hWndNewTB, _T(TOOLBAND_NAME)); |
|
SendMessage(hWndNewTB, TB_SETIMAGELIST, 0, (LPARAM)gImagelist); |
|
SendMessage(hWndNewTB, TB_SETBUTTONWIDTH, 0, MAKELONG(0, 100)); |
|
|
|
while (SendMessage(hWndOldTB, TB_GETBUTTON, i, (LPARAM)&button)) { |
|
LONG lResult = SendMessage(hWndOldTB, TB_GETBUTTONTEXT, (WPARAM) button.idCommand, NULL); |
|
if (lResult >= 0) { |
|
TCHAR *szTmp = new TCHAR[lResult + 2]; |
|
SendMessage(hWndOldTB, TB_GETBUTTONTEXT, (WPARAM) button.idCommand, (LPARAM) szTmp); |
|
szTmp[lResult+1] = 0; |
|
|
|
button.iString = (INT_PTR)szTmp; |
|
//int stringID = SendMessage(hWndNewTB, TB_ADDSTRING, (WPARAM)NULL, (LPARAM) szTmp); |
|
//button.iString = stringID; |
|
SendMessage(hWndNewTB, TB_INSERTBUTTON, (WPARAM)-1, (LPARAM)&button); |
|
|
|
delete szTmp; |
|
} |
|
else |
|
SendMessage(hWndNewTB, TB_INSERTBUTTON, (WPARAM)-1, (LPARAM)&button); |
|
|
|
++i; |
|
} |
|
} |
|
|
|
BOOL RealDeleteMenu(HMENU menu, UINT pos) |
|
{ |
|
if (HMENU m = GetSubMenu(menu, pos)) |
|
DestroyMenu(m); |
|
|
|
return DeleteMenu(menu, pos, MF_BYPOSITION); |
|
} |
|
|
|
// Build Rebar |
|
void BuildRebar(HWND hWndTB) |
|
{ |
|
InitImageList(gImagelist); |
|
|
|
HIMAGELIST siteIcons = kPlugin.kFuncs->GetIconList(); |
|
|
|
BOOL useSiteicon = TRUE; |
|
kPlugin.kFuncs->GetPreference(PREF_BOOL, "kmeleon.plugins.bookmarks.displaySiteicon", &useSiteicon, &useSiteicon); |
|
useSiteicon &= (siteIcons != NULL); |
|
|
|
CBookmarkNode *toolbarNode = gBookmarkRoot->FindSpecialNode(BOOKMARK_FLAG_TB); |
|
|
|
SetWindowText(hWndTB, _T(TOOLBAND_NAME)); |
|
|
|
//SendMessage(hWndTB, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS); |
|
|
|
SendMessage(hWndTB, TB_SETIMAGELIST, 0, (LPARAM)gImagelist); |
|
|
|
SendMessage(hWndTB, TB_SETBUTTONWIDTH, 0, MAKELONG(0, 100)); |
|
|
|
//int stringID; |
|
CBookmarkNode *child; |
|
int curButton = 0; |
|
|
|
for (child=toolbarNode->child; child; child=child->next) { |
|
if (++curButton > TOOLBAND_MAX_BUTTONS) { |
|
break; // Simple fix to prevent massive toolbar folders from bringing KM to its knees |
|
} |
|
|
|
if (child->type == BOOKMARK_SEPARATOR) { |
|
TBBUTTON button; |
|
button.iBitmap = 0; |
|
button.idCommand = 0; |
|
button.fsState = TBSTATE_ENABLED; |
|
button.fsStyle = TBSTYLE_SEP; |
|
button.dwData = 0; |
|
button.iString = 0; |
|
SendMessage(hWndTB, TB_INSERTBUTTON, (WPARAM)-1, (LPARAM)&button); |
|
continue; |
|
} |
|
|
|
// condense the title and escape ampersands |
|
TCHAR *buttonString = fixString(CUTF8_to_T(child->text.c_str()), gMaxTBSize); |
|
|
|
//stringID = SendMessage(hWndTB, TB_ADDSTRING, (WPARAM)NULL, (LPARAM)buttonString); |
|
|
|
|
|
TBBUTTON button = {0}; |
|
//button.iString = stringID; |
|
button.iString = (int)buttonString; |
|
button.fsState = TBSTATE_ENABLED; |
|
button.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE; |
|
|
|
if (child->type == BOOKMARK_FOLDER){ |
|
// toolbar may not be contained in bookmark menu, so we can't just use its submenus |
|
HMENU childMenu = CreatePopupMenu(); |
|
BuildMenu(childMenu, child, false); |
|
button.idCommand = MENU_TO_COMMAND((UINT)childMenu); |
|
button.iBitmap = IMAGE_FOLDER_CLOSED; |
|
button.fsStyle |= TBSTYLE_DROPDOWN; |
|
button.dwData = (DWORD_PTR)childMenu; |
|
} |
|
else { |
|
button.idCommand = child->id; |
|
button.iBitmap = IMAGE_BOOKMARK; |
|
if (useSiteicon) { |
|
UINT idx = GetSiteIcon(child); |
|
if (idx>0) { |
|
HICON icon = ImageList_GetIcon(siteIcons, idx, ILD_NORMAL); |
|
if (icon) { |
|
idx = ImageList_AddIcon(gImagelist, icon); |
|
if (idx != -1) button.iBitmap = idx; |
|
DestroyIcon(icon); |
|
} |
|
} |
|
} |
|
button.dwData = NULL; |
|
} |
|
|
|
SendMessage(hWndTB, TB_INSERTBUTTON, (WPARAM)-1, (LPARAM)&button); |
|
free(buttonString); |
|
} |
|
|
|
if (bChevronEnabled) { |
|
TBBUTTON button = {0}; |
|
button.fsState = TBSTATE_ENABLED; |
|
button.fsStyle = TBSTYLE_SEP; |
|
SendMessage(hWndTB, TB_INSERTBUTTON, (WPARAM)0, (LPARAM)&button); |
|
|
|
button.iBitmap = IMAGE_CHEVRON; |
|
button.idCommand = nDropdownCommand; |
|
button.fsState = TBSTATE_ENABLED; |
|
button.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN; |
|
button.iString = -1; |
|
SendMessage(hWndTB, TB_INSERTBUTTON, (WPARAM)0, (LPARAM)&button); |
|
} |
|
} |
|
|
|
void Rebuild() { |
|
// delete the old bookmarks from the menu (FIXME - needs to be more robust than "delete everything after the first bookmark position" - there may be normal menu items there (if the user is weird)) |
|
while (RealDeleteMenu(gMenuBookmarks, nFirstBookmarkPosition)); |
|
// and rebuild |
|
BuildMenu(gMenuBookmarks, gBookmarkRoot->FindSpecialNode(BOOKMARK_FLAG_BM), false); |
|
|
|
int ideal = 0; |
|
|
|
std::map<HWND, HWND>::iterator it = gToolbarList.begin(); |
|
// It's possible to edit bookmark, without having a toolbar (loader) |
|
if (it == gToolbarList.end()) |
|
return; |
|
|
|
HWND refToolbar = it->second; |
|
|
|
// delete the old rebar and the menus. |
|
TBBUTTON button; |
|
do |
|
{ |
|
if (SendMessage(refToolbar, TB_GETBUTTON, (WPARAM)0, (LPARAM)&button)) |
|
if (button.dwData) { |
|
DestroyMenu((HMENU)button.dwData); |
|
} |
|
} while (SendMessage(refToolbar, TB_DELETEBUTTON, 0, 0)); |
|
|
|
// and rebuild |
|
BuildRebar(refToolbar); |
|
|
|
// Compute the width needed for the toolbar |
|
int iCount, iButtonCount = SendMessage(refToolbar, TB_BUTTONCOUNT, 0,0); |
|
for ( iCount = 0 ; iCount < iButtonCount ; iCount++ ) |
|
{ |
|
RECT rectButton; |
|
SendMessage(refToolbar, TB_GETITEMRECT, iCount, (LPARAM)&rectButton); |
|
ideal += rectButton.right - rectButton.left; |
|
} |
|
|
|
|
|
// Copy the new toolbar to the other windows. |
|
while (it != gToolbarList.end()) |
|
{ |
|
HWND toolbar = it->second; |
|
|
|
if (toolbar != refToolbar) |
|
{ |
|
while (SendMessage(toolbar, TB_DELETEBUTTON, 0 /*index*/, 0)) ; |
|
CopyRebar(toolbar, refToolbar); |
|
} |
|
|
|
HWND hReBar = FindWindowEx(it->first, NULL, REBARCLASSNAME, NULL); |
|
int uBandCount = SendMessage(hReBar, RB_GETBANDCOUNT, 0, 0); |
|
REBARBANDINFO rb; |
|
rb.cbSize = sizeof(REBARBANDINFO); |
|
rb.fMask = RBBIM_CHILD; |
|
|
|
// Update the ideal size |
|
for(int x=0;x < uBandCount;x++) |
|
{ |
|
if (!SendMessage(hReBar, RB_GETBANDINFO, (WPARAM) x, (LPARAM) &rb)) |
|
continue; |
|
|
|
if (rb.hwndChild == toolbar) |
|
{ |
|
rb.fMask = RBBIM_IDEALSIZE; |
|
rb.cxIdeal = ideal; |
|
SendMessage(hReBar, RB_SETBANDINFO, x, (LPARAM)&rb); |
|
break; |
|
} |
|
} |
|
++it; |
|
} |
|
|
|
#if 0 |
|
// need to rebuild the rebar, too, in case it had submenus (whose ids are now invalid) |
|
if (ghWndTB) { |
|
// delete the old rebar |
|
while (SendMessage(ghWndTB, TB_DELETEBUTTON, 0 /*index*/, 0)); |
|
// and rebuild |
|
BuildRebar(ghWndTB); |
|
} |
|
#endif |
|
|
|
// FIXME - Is this needed? Hm, if anywhere, in WndProc, below, in the nAddCommand/nAddToolbarCommand/nEditCommand cases... but then it's still only one window, and the others don't get the call, so... heck, it works without it. It will stay until someone complains. :) |
|
// DrawMenuBar(hWnd); |
|
} |
|
|
|
void Fill_Combo(HWND hWnd, CBookmarkNode* node, unsigned short depth=0) |
|
{ |
|
for (CBookmarkNode* child=node->child; child; child=child->next) { |
|
if (child->type == BOOKMARK_FOLDER) { |
|
std::basic_string<TCHAR> title = CUTF8_to_T(child->text.c_str()); |
|
title.insert(0, depth*2, ' '); |
|
int index = SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)title.c_str()); |
|
SendMessage(hWnd, CB_SETITEMDATA, index, (LPARAM)child); |
|
Fill_Combo(hWnd, child, depth+1); |
|
} |
|
} |
|
} |
|
|
|
void addLink(const char *url, const char *title, const char* nick, const char* iconurl, CBookmarkNode* node) |
|
{ |
|
if (!node || node->type!=BOOKMARK_FOLDER) return; |
|
node->AddChild(new CBookmarkNode(kPlugin.kFuncs->GetCommandIDs(1), title, url, nick, "", "", BOOKMARK_BOOKMARK, time(NULL), 0, 0, "", "", "", iconurl)); |
|
SaveBM(gBookmarkFile); |
|
Rebuild(); |
|
} |
|
|
|
int CALLBACK AddProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
static HWND hWnd = 0; |
|
|
|
switch (uMsg) { |
|
case WM_INITDIALOG: { |
|
hWnd = (HWND)lParam; |
|
kmeleonDocInfo *dInfo = kPlugin.kFuncs->GetDocInfo(hWnd); |
|
if (dInfo && dInfo->url) { |
|
if (dInfo->title) { |
|
SetDlgItemText(hDlg, IDC_TITLE, CUTF8_to_T(dInfo->title)); |
|
}else{ |
|
SetDlgItemText(hDlg, IDC_TITLE, CUTF8_to_T(dInfo->url)); |
|
} |
|
} |
|
|
|
HWND combo = GetDlgItem(hDlg, IDC_FOLDER); |
|
int index = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)_T("Bookmarks")); |
|
SendMessage(combo, CB_SETITEMDATA, index, (LPARAM)gBookmarkRoot); |
|
Fill_Combo(combo, gBookmarkRoot, 1); |
|
|
|
CBookmarkNode *defaultNode = gBookmarkRoot->FindSpecialNode(BOOKMARK_FLAG_NB); |
|
int count = SendMessage(combo, CB_GETCOUNT, 0, 0); |
|
for (index=0;index<count;index++) { |
|
CBookmarkNode* node = (CBookmarkNode*)SendMessage(combo, CB_GETITEMDATA, index, 0); |
|
if (defaultNode == node) { |
|
SendMessage(combo, CB_SETCURSEL, index, 0); |
|
break; |
|
} |
|
} |
|
|
|
// Set the height |
|
RECT rect; |
|
GetClientRect(combo, &rect); |
|
int height = rect.bottom + 4 + SendMessage(combo, CB_GETITEMHEIGHT, 0, 0) * 10; |
|
SetWindowPos(combo, 0,0,0,rect.right,height,SWP_NOMOVE|SWP_NOZORDER); |
|
|
|
return TRUE; |
|
} |
|
|
|
case WM_COMMAND: |
|
switch (LOWORD(wParam)) { |
|
case IDOK: { |
|
kmeleonDocInfo *dInfo = kPlugin.kFuncs->GetDocInfo(hWnd); |
|
if (dInfo) { |
|
TCHAR title[1024], nick[128]; |
|
GetDlgItemText(hDlg, IDC_TITLE, title, sizeof(title)); |
|
GetDlgItemText(hDlg, IDC_NICK, nick, sizeof(nick)); |
|
|
|
HWND combo = GetDlgItem(hDlg, IDC_FOLDER); |
|
int index = SendMessage(combo, CB_GETCURSEL, 0, 0); |
|
CBookmarkNode* node = (CBookmarkNode*)SendMessage(combo, CB_GETITEMDATA, index, 0); |
|
|
|
addLink(dInfo->url, CT_to_UTF8(title), CT_to_UTF8(nick), dInfo->iconurl, node); |
|
} |
|
EndDialog( hDlg, IDOK ); |
|
break; |
|
} |
|
case IDCANCEL: |
|
EndDialog( hDlg, IDCANCEL ); |
|
break; |
|
} |
|
} |
|
return FALSE; |
|
} |
|
|
|
int addLink(const char *url, const char *title, int flag, const char* iconurl) |
|
{ |
|
if (!url || !(*url)) |
|
return false; |
|
|
|
CBookmarkNode *addNode = gBookmarkRoot->FindSpecialNode(flag); |
|
char *pszUrl = DecodeString(url); |
|
char *pszTxt = DecodeString(title ? (*title ? title : url) : url); |
|
addNode->AddChild(new CBookmarkNode(kPlugin.kFuncs->GetCommandIDs(1), pszTxt, pszUrl, "", "", "", BOOKMARK_BOOKMARK, time(NULL),0,0,"","","",iconurl)); |
|
if (pszUrl) |
|
free(pszUrl); |
|
if (pszTxt) |
|
free(pszTxt); |
|
SaveBM(gBookmarkFile); |
|
|
|
Rebuild(); |
|
|
|
return true; |
|
} |
|
|
|
|
|
static TCHAR szInput[256]; |
|
static TCHAR *pszTitle = 0; |
|
static TCHAR *pszPrompt = 0; |
|
|
|
BOOL CALLBACK |
|
PromptDlgProc( HWND hwnd, |
|
UINT Message, |
|
WPARAM wParam, |
|
LPARAM lParam ) |
|
{ |
|
switch (Message) { |
|
case WM_INITDIALOG: |
|
SetWindowText( hwnd, pszTitle ? pszTitle : _T("Smart bookmark") ); |
|
SetDlgItemText(hwnd, IDC_SEARCHTEXT, pszPrompt ? pszPrompt : _T("")); |
|
return TRUE; |
|
case WM_COMMAND: |
|
switch (LOWORD(wParam)) { |
|
case IDOK: |
|
GetDlgItemText(hwnd, IDC_INPUT, szInput, 256); |
|
EndDialog( hwnd, IDOK ); |
|
break; |
|
case IDCANCEL: |
|
EndDialog( hwnd, IDCANCEL ); |
|
break; |
|
} |
|
break; |
|
|
|
default: |
|
return FALSE; |
|
} |
|
return TRUE; |
|
} |
|
|
|
void OpenURL(char *url, int mode = 0) |
|
{ |
|
char szOpenURLcmd[80]; |
|
const char* pref; |
|
switch (mode) { |
|
|
|
case 1: pref = PREFERENCE_BOOKMARKS_OPENURLM; break; |
|
case 2: pref = PREFERENCE_BOOKMARKS_OPENURLR; break; |
|
case 0: |
|
default: |
|
pref = PREFERENCE_BOOKMARKS_OPENURL; break; |
|
} |
|
|
|
kPlugin.kFuncs->GetPreference(PREF_STRING, pref, szOpenURLcmd, (char*)""); |
|
|
|
if (!*szOpenURLcmd) { |
|
if (mode != 0) return; |
|
kPlugin.kFuncs->NavigateTo(url, OPEN_NORMAL, NULL); |
|
return; |
|
} |
|
|
|
char *plugin = szOpenURLcmd; |
|
char *parameter = strchr(szOpenURLcmd, '('); |
|
if (parameter) { |
|
*parameter++ = 0; |
|
char *close = strchr(parameter, ')'); |
|
if (close) { |
|
*close = 0; |
|
|
|
if (kPlugin.kFuncs->SendMessage(plugin, PLUGIN_NAME, parameter, (long)url, 0)) |
|
return; |
|
} |
|
} |
|
|
|
int idOpen = kPlugin.kFuncs->GetID(szOpenURLcmd); |
|
if (idOpen == kPlugin.kFuncs->GetID("ID_OPEN_LINK")) { |
|
kPlugin.kFuncs->NavigateTo(url, OPEN_NORMAL, NULL); |
|
}else if (idOpen == kPlugin.kFuncs->GetID("ID_OPEN_LINK_IN_BACKGROUND")) { |
|
kPlugin.kFuncs->NavigateTo(url, OPEN_BACKGROUND, NULL); |
|
}else if (idOpen == kPlugin.kFuncs->GetID("ID_OPEN_LINK_IN_NEW_WINDOW")) { |
|
kPlugin.kFuncs->NavigateTo(url, OPEN_NEW, NULL); |
|
}else if (idOpen == kPlugin.kFuncs->GetID("ID_OPEN_LINK_IN_NEW_TAB")) { |
|
kPlugin.kFuncs->NavigateTo(url, OPEN_NEWTAB, NULL); |
|
}else if (idOpen == kPlugin.kFuncs->GetID("ID_OPEN_LINK_IN_BACKGROUNDTAB")) { |
|
kPlugin.kFuncs->NavigateTo(url, OPEN_BACKGROUNDTAB, NULL); |
|
} |
|
} |
|
|
|
void OpenBookmark(CBookmarkNode* node, HWND hWnd = NULL, int mode = 0) |
|
{ |
|
if (!node) return; |
|
|
|
node->lastVisit = time(NULL); |
|
gBookmarksModified = true; // this doesn't call for instant saving, it can wait until we add/edit/quit |
|
|
|
if (node->url.c_str() == NULL || *node->url.c_str() == 0) |
|
return; |
|
|
|
char *str = strdup(node->url.c_str()); |
|
char *ptr = strstr(str, "%s"); |
|
if (ptr) { |
|
char buff[INTERNET_MAX_URL_LENGTH]; |
|
*ptr = 0; |
|
strcpy(buff, str); |
|
ptr += 2; |
|
|
|
if (pszTitle) free(pszTitle); |
|
if (pszPrompt) free(pszPrompt); |
|
pszTitle = t_from_utf8( node->text.c_str() ); |
|
pszPrompt = t_from_utf8( node->desc.c_str() ); |
|
|
|
int ok = gLoc->DialogBoxParam(MAKEINTRESOURCE(IDD_SMARTBOOKMARK), |
|
hWnd, (DLGPROC)PromptDlgProc, NULL); |
|
PostMessage(hWnd, WM_NULL, 0, 0); |
|
if (ok == IDOK && *szInput) { |
|
strcat(buff, CT_to_UTF8(szInput)); |
|
strcat(buff, ptr); |
|
OpenURL(buff, mode); |
|
} |
|
} |
|
else { |
|
OpenURL(str, mode); |
|
} |
|
free(str); |
|
} |
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { |
|
// store these in static vars so that the BeginHotTrack call can access them |
|
static NMTOOLBAR tbhdr; |
|
static NMHDR hdr; |
|
static HMENU lastMenu = NULL; |
|
|
|
if (message == WM_SETFOCUS) { |
|
hWndFront = hWnd; |
|
} |
|
else if (message == WM_COMMAND) { |
|
WORD command = LOWORD(wParam); |
|
|
|
if (command == nConfigCommand) { |
|
Config(hWnd); |
|
return true; |
|
} |
|
else if (command == nAddCommand) { |
|
|
|
kmeleonDocInfo *dInfo = kPlugin.kFuncs->GetDocInfo(hWnd); |
|
if (!dInfo || !dInfo->url || strncmp(dInfo->url, "wyciwyg", 7) == 0) { |
|
::MessageBox(NULL, gLoc->GetString(IDS_CANT_BOOKMARK), gLoc->GetString(IDS_CANT_BOOKMARK_TITLE), MB_OK); |
|
return true; |
|
} |
|
BOOL ask = TRUE; |
|
kPlugin.kFuncs->GetPreference(PREF_BOOL, PREFERENCE_BOOKMARK_ASKFOLDER, &ask, &ask); |
|
|
|
if (ask) { |
|
gLoc->DialogBoxParam(MAKEINTRESOURCE(IDD_ADDBOOKMARK), NULL, AddProc, (LPARAM)kPlugin.kFuncs->GetCurrent(hWnd)); |
|
} |
|
else { |
|
addLink(dInfo->url, dInfo->title, BOOKMARK_FLAG_NB, dInfo->iconurl); |
|
} |
|
return true; |
|
} |
|
else if (command == nAddLinkCommand) { |
|
|
|
int retLen = kPlugin.kFuncs->GetGlobalVar(PREF_STRING, "LinkURL", NULL); |
|
if (retLen) { |
|
char *title = 0; |
|
char *url = new char[retLen+1]; |
|
kPlugin.kFuncs->GetGlobalVar(PREF_STRING, "LinkURL", url); |
|
|
|
retLen = kPlugin.kFuncs->GetWindowVar(hWnd, Window_LinkTitle, NULL); |
|
if (retLen > 0) { |
|
title = new char[retLen+1]; |
|
kPlugin.kFuncs->GetWindowVar(hWnd, Window_LinkTitle, title); |
|
} |
|
else title = url; |
|
|
|
addLink(url, title, BOOKMARK_FLAG_NB); |
|
delete url; |
|
if (title!=url) delete title; |
|
} |
|
return true; |
|
} |
|
else if (command == nAddToolbarCommand) { |
|
kmeleonDocInfo *dInfo = kPlugin.kFuncs->GetDocInfo(hWnd); |
|
if (dInfo) { |
|
addLink(dInfo->url, dInfo->title, BOOKMARK_FLAG_TB, dInfo->iconurl); |
|
} |
|
return true; |
|
} |
|
else if (command == nEditCommand) { |
|
if (ghWndEdit) { |
|
ShowWindow(ghWndEdit, SW_RESTORE); |
|
BringWindowToTop(ghWndEdit); |
|
} |
|
else { |
|
ghWndEdit = gLoc->CreateDialogParam(MAKEINTRESOURCE(IDD_EDIT_BOOKMARKS), NULL, EditProc, 0); |
|
} |
|
return true; |
|
} |
|
else if (command == wm_deferbringtotop) { |
|
BringWindowToTop(hWnd); |
|
return true; |
|
} |
|
else if (command == nAddBookmarkHereCommand) { |
|
CBookmarkNode* node = gBookmarkRoot->FindFolder(lastMenu); |
|
if (node) { |
|
kmeleonDocInfo *dInfo = kPlugin.kFuncs->GetDocInfo(hWnd); |
|
if (dInfo) addLink(dInfo->url, dInfo->title, "", dInfo->iconurl, node); |
|
} |
|
return true; |
|
} |
|
else if (CBookmarkNode *node = gBookmarkRoot->FindNode(command)) { |
|
OpenBookmark(node, hWnd, lParam); |
|
return true; |
|
} |
|
|
|
} |
|
else if (message == WM_NOTIFY) { |
|
hdr = *((LPNMHDR)lParam); |
|
if (hdr.code == (UINT) TBN_DROPDOWN) { |
|
tbhdr = *((LPNMTOOLBAR)lParam); |
|
|
|
// this is the little down arrow thing |
|
if (tbhdr.iItem == (int) nDropdownCommand){ |
|
RECT rc; |
|
WPARAM index = 0; |
|
SendMessage(tbhdr.hdr.hwndFrom, TB_GETITEMRECT, index, (LPARAM) &rc); |
|
POINT pt = { rc.left, rc.bottom }; |
|
ClientToScreen(tbhdr.hdr.hwndFrom, &pt); |
|
TrackPopupMenu((HMENU)gMenuBookmarks, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL); |
|
} |
|
else if (IsMenu((HMENU)(tbhdr.iItem-SUBMENU_OFFSET))){ |
|
TCHAR toolbarName[11]; |
|
GetWindowText(tbhdr.hdr.hwndFrom, toolbarName, 10); |
|
if (_tcscmp(toolbarName, _T(TOOLBAND_NAME)) != 0) { |
|
// oops, this isn't our toolbar |
|
return CallWindowProc(KMeleonWndProc, hWnd, message, wParam, lParam); |
|
} |
|
|
|
// post a message to defer exceution of BeginHotTrack |
|
PostMessage(hWnd, WM_DEFERHOTTRACK, (WPARAM) NULL, (LPARAM) NULL); |
|
|
|
return DefWindowProc(hWnd, message, wParam, lParam); |
|
} |
|
} |
|
} |
|
else if (message == WM_INITMENUPOPUP) { |
|
lastMenu = (HMENU)wParam; |
|
} |
|
else if (message == WM_DEFERHOTTRACK) { |
|
BeginHotTrack(&tbhdr, kPlugin.hDllInstance, hWnd); |
|
return true; |
|
} |
|
else if (message == WM_MENUSELECT) { |
|
UINT id = LOWORD(wParam); |
|
|
|
if (id >= nConfigCommand && id < nDropdownCommand) { |
|
if (id == nConfigCommand) |
|
kPlugin.kFuncs->SetStatusBarText(CT_to_UTF8(gLoc->GetString(IDS_CONFIGURE))); |
|
else if (id == nAddCommand) |
|
kPlugin.kFuncs->SetStatusBarText(CT_to_UTF8(gLoc->GetString(IDS_ADD))); |
|
else if (id == nAddLinkCommand) |
|
kPlugin.kFuncs->SetStatusBarText(CT_to_UTF8(gLoc->GetString(IDS_ADDLINK))); |
|
else if (id == nEditCommand) |
|
kPlugin.kFuncs->SetStatusBarText(CT_to_UTF8(gLoc->GetString(IDS_EDIT))); |
|
return true; |
|
} |
|
else if (id > 0) { |
|
CBookmarkNode *node = gBookmarkRoot->FindNode(id); |
|
if (node) { |
|
kPlugin.kFuncs->SetStatusBarText(node->url.c_str()); |
|
return true; |
|
} |
|
} |
|
// this would be a hack to clean the status bar for separators, popups |
|
// (they work (clear the status bar) for CMenu-added separators/popups, |
|
// but not when they are added via standard win32 calls...) |
|
else { |
|
kPlugin.kFuncs->SetStatusBarText(""); |
|
} |
|
} |
|
else if (message == TB_MBUTTONDOWN || message == TB_RBUTTONDOWN) { |
|
int command = LOWORD(wParam); |
|
if (CBookmarkNode *node = gBookmarkRoot->FindNode(command)) { |
|
OpenBookmark(node, hWnd, message-(TB_MBUTTONDOWN) + 1); |
|
return true; |
|
} |
|
} |
|
|
|
return CallWindowProc(KMeleonWndProc, hWnd, message, wParam, lParam); |
|
}
|
|
|