Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / netidmgr_plugin / afsicon.c
blob54cb6dd85a90d91e0efd963d73c471f206ae27f9
2 #define NOSTRSAFE
3 #include "afscred.h"
4 #include "AFS_component_version_number.h"
5 #include <tchar.h>
6 #include <shellapi.h>
7 #include <shlwapi.h>
8 #include <htmlhelp.h>
9 #include <strsafe.h>
10 #include <assert.h>
12 static ATOM message_window_class = 0;
13 static HWND notifier_window = NULL;
14 static volatile BOOL notification_icon_added = FALSE;
16 #define TOKEN_ICON_ID 1
17 #define TOKEN_MESSAGE_ID WM_USER
19 static khm_int32
20 get_default_notifier_action(void)
22 khm_int32 cmd = KHUI_ACTION_OPEN_APP;
24 khc_read_int32(NULL, L"CredWindow\\NotificationAction", &cmd);
26 return cmd;
29 static BOOL
30 get_release_notes(wchar_t rpath[MAX_PATH])
32 BOOL rv = FALSE;
33 HKEY hk_client = NULL;
34 wchar_t cpath[MAX_PATH];
35 DWORD cb_data;
37 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
38 L"Software\\TransarcCorporation\\AFS Client\\CurrentVersion",
39 0, KEY_READ, &hk_client) != ERROR_SUCCESS)
40 return FALSE;
42 cb_data = sizeof(cpath);
43 if (RegQueryValueEx(hk_client, L"PathName", NULL, NULL, (LPBYTE) cpath, &cb_data) != ERROR_SUCCESS)
44 goto done;
46 cpath[min(cb_data, MAX_PATH - 1)] = L'\0';
48 if (!PathRemoveFileSpec(cpath))
49 goto done;
51 if (!PathAppend(cpath, L"Documentation"))
52 goto done;
54 if (!PathAppend(cpath, L"ReleaseNotes.chm"))
55 goto done;
57 if (!PathCanonicalize(rpath, cpath))
58 goto done;
60 if (!PathFileExists(rpath))
61 goto done;
63 rv = TRUE;
65 done:
66 if (hk_client)
67 RegCloseKey(hk_client);
69 return rv;
72 static void
73 handle_select(void)
75 NOTIFYICONDATA idata;
76 khm_int32 cmd;
78 cmd = get_default_notifier_action();
80 khui_action_trigger(cmd, NULL);
82 ZeroMemory(&idata, sizeof(idata));
84 Shell_NotifyIcon(NIM_SETFOCUS, &idata);
87 static void
88 prepare_context_menu(HMENU hmenu)
90 khm_int32 cmd;
91 wchar_t caption[128];
92 wchar_t relnotes[MAX_PATH];
94 cmd = get_default_notifier_action();
96 if (cmd == KHUI_ACTION_NEW_CRED)
97 LoadString(hResModule, IDS_ACT_NEW, caption, ARRAYLENGTH(caption));
98 else
99 LoadString(hResModule, IDS_ACT_OPEN, caption, ARRAYLENGTH(caption));
101 ModifyMenu(hmenu, ID_DEFAULT, MF_STRING|MF_BYCOMMAND, ID_DEFAULT, caption);
102 SetMenuDefaultItem(hmenu, ID_DEFAULT, FALSE);
104 if (!get_release_notes(relnotes))
105 RemoveMenu(hmenu, ID_RELEASENOTES, MF_BYCOMMAND);
108 static void
109 handle_context_menu(void)
111 POINT pt;
112 HMENU hMenu;
113 HMENU hMenuBar;
115 GetCursorPos(&pt);
117 hMenuBar = LoadMenu(hResModule, MAKEINTRESOURCE(IDR_CTXMENU));
118 hMenu = GetSubMenu(hMenuBar, 0);
120 if (hMenu) {
121 prepare_context_menu(hMenu);
122 TrackPopupMenu(hMenu, TPM_NONOTIFY, pt.x, pt.y, 0, notifier_window, NULL);
126 NOTIFYICONDATA idata;
127 ZeroMemory(&idata, sizeof(idata));
128 Shell_NotifyIcon(NIM_SETFOCUS, &idata);
132 static LRESULT CALLBACK
133 notifier_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
135 if (uMsg == TOKEN_MESSAGE_ID) {
136 switch (lParam) {
137 case NIN_SELECT:
138 case NIN_KEYSELECT:
140 handle_select();
141 return TRUE;
143 case WM_CONTEXTMENU:
144 handle_context_menu();
145 return TRUE;
147 default:
148 return FALSE;
151 else if (uMsg == WM_COMMAND) {
152 switch (LOWORD(wParam)) {
153 case ID_DEFAULT:
155 khm_int32 cmd;
157 cmd = get_default_notifier_action();
159 khui_action_trigger(cmd, NULL);
161 return TRUE;
163 case ID_SHOWHELP:
165 afs_html_help(notifier_window, L"::/html/welcome.htm", HH_DISPLAY_TOPIC, 0);
167 return TRUE;
169 case ID_RELEASENOTES:
171 wchar_t relnotes[MAX_PATH];
173 if (get_release_notes(relnotes))
174 HtmlHelp(GetDesktopWindow(), relnotes, HH_DISPLAY_TOC, 0);
176 return TRUE;
179 return DefWindowProc(hwnd, uMsg, wParam, lParam);
182 static void
183 initialize_if_necessary(void)
185 if (message_window_class == 0) {
186 WNDCLASSEX c = {
187 sizeof(WNDCLASSEX), /* cbSize */
188 0, /* style */
189 notifier_wnd_proc, /* lpfnWndProc */
190 0, /* cbClsExtra */
191 0, /* cbWndExtra */
192 NULL, /* hinstance */
193 NULL, /* hIcon */
194 NULL, /* hCursor */
195 NULL, /* hbrBackground */
196 NULL, /* lpszMenuName */
197 L"OpenAFSTokenStateIconNotifier", /* lpszClassName */
198 NULL, /* hIconSm */
201 c.hInstance = hInstance;
202 message_window_class = RegisterClassEx(&c);
205 if (notifier_window == NULL && message_window_class != 0) {
206 notifier_window = CreateWindow(MAKEINTATOM(message_window_class),
207 L"OpenAFSTokenStateIconNotifierWindow",
208 0, 0, 0, 0, 0,
209 HWND_MESSAGE,
210 NULL,
211 hInstance,
212 NULL);
215 assert(notifier_window != NULL);
217 if (!notification_icon_added && notifier_window != NULL) {
218 NOTIFYICONDATA idata;
220 ZeroMemory(&idata, sizeof(idata));
222 idata.cbSize = sizeof(idata);
223 idata.hWnd = notifier_window;
224 idata.uID = TOKEN_ICON_ID;
225 idata.uFlags = NIF_ICON | NIF_MESSAGE;
226 idata.uCallbackMessage = TOKEN_MESSAGE_ID;
227 idata.hIcon = (HICON) LoadImage(hResModule, MAKEINTRESOURCE(IDI_CRED_NONE),
228 IMAGE_ICON, 0, 0,
229 LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED);
230 notification_icon_added = Shell_NotifyIcon(NIM_ADD, &idata);
232 idata.cbSize = sizeof(idata);
233 idata.uVersion = NOTIFYICON_VERSION;
235 Shell_NotifyIcon(NIM_SETVERSION, &idata);
237 assert(notification_icon_added);
241 void
242 afs_remove_icon(void)
244 NOTIFYICONDATA idata;
246 ZeroMemory(&idata, sizeof(idata));
248 idata.cbSize = sizeof(idata);
249 idata.hWnd = notifier_window;
250 idata.uID = TOKEN_ICON_ID;
251 Shell_NotifyIcon(NIM_DELETE, &idata);
252 notification_icon_added = FALSE;
255 static void
256 set_tooltip_and_icon(UINT tooltip_text, const wchar_t * postfix, UINT icon_id)
258 NOTIFYICONDATA idata;
259 wchar_t buf[ARRAYLENGTH(idata.szTip)];
261 ZeroMemory(&idata, sizeof(idata));
263 idata.cbSize = sizeof(idata);
264 idata.hWnd = notifier_window;
265 idata.uID = TOKEN_ICON_ID;
266 idata.uFlags = NIF_ICON | NIF_TIP;
267 idata.hIcon = (HICON) LoadImage(hResModule, MAKEINTRESOURCE(icon_id),
268 IMAGE_ICON, 0, 0,
269 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
270 if (tooltip_text != 0) {
271 LoadString(hResModule, tooltip_text, buf, ARRAYLENGTH(buf));
273 StringCbPrintf(idata.szTip, sizeof(idata.szTip),
274 L"%s%s%s%s",
275 (tooltip_text != 0)? buf : L"",
276 (postfix != NULL)? postfix : L"",
277 (tooltip_text != 0 || postfix != NULL)? L"\n": L"",
278 _T(AFS_VERINFO_BUILD));
280 Shell_NotifyIcon(NIM_MODIFY, &idata);
283 struct state_data {
284 enum notification_icon_state state;
285 khm_handle credset;
288 #define COLLECT_STR_LEN 256
290 static khm_int32 KHMAPI
291 collect_cell_names(khm_handle cred, void * rock)
293 wchar_t *str = (wchar_t *) rock;
294 wchar_t cell[KCDB_MAXCCH_NAME] = L"";
295 FILETIME ft_now;
296 FILETIME ft_expire;
297 khm_size cb;
299 cb = sizeof(ft_expire);
300 if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, NULL, &ft_expire, &cb)))
301 return KHM_ERROR_SUCCESS;
303 GetSystemTimeAsFileTime(&ft_now);
304 if (CompareFileTime(&ft_now, &ft_expire) >= 0)
305 return KHM_ERROR_SUCCESS;
307 cb = sizeof(cell);
309 if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, afs_attr_cell, NULL, cell, &cb)) &&
310 cell[0]) {
311 StringCchCat(str, COLLECT_STR_LEN, cell);
312 StringCchCat(str, COLLECT_STR_LEN, L"\n");
315 return KHM_ERROR_SUCCESS;
318 static khm_int32 KHMAPI
319 set_state_from_ui_thread(HWND hwnd_main, void * stuff)
321 struct state_data * d = (struct state_data *) stuff;
323 initialize_if_necessary();
325 switch (d->state) {
326 case AFSICON_REPORT_TOKENS:
328 wchar_t cells[COLLECT_STR_LEN] = L"";
330 kcdb_credset_apply(d->credset, collect_cell_names, cells);
332 if (cells[0] == L'\0') {
333 set_tooltip_and_icon(IDS_CRED_TT_NONE, NULL, IDI_CRED_NONE);
334 break;
337 set_tooltip_and_icon(0, cells, IDI_CRED_OK);
339 break;
341 case AFSICON_SERVICE_STOPPED:
342 set_tooltip_and_icon(IDS_CRED_TT_NOS, NULL, IDI_CRED_SVCSTOP);
343 break;
345 case AFSICON_SERVICE_ERROR:
346 set_tooltip_and_icon(IDS_CRED_TT_SERR, NULL, IDI_CRED_BROKEN);
347 break;
349 default:
350 assert(FALSE);
353 (void) hwnd_main; /* unreferenced */
355 return KHM_ERROR_SUCCESS;
358 void
359 afs_icon_set_state(enum notification_icon_state state,
360 khm_handle credset_with_tokens)
362 struct state_data d;
364 #if KH_VERSION_API < 7
365 if (pkhui_request_UI_callback == NULL)
366 return;
367 #endif
369 d.state = state;
370 d.credset = credset_with_tokens;
372 if (notification_icon_added) {
373 set_state_from_ui_thread(NULL, &d);
374 } else {
375 khui_request_UI_callback(set_state_from_ui_thread, &d);