import-fs-formatting-to-windows-20031207
[openafs.git] / src / WINNT / client_config / tab_prefs.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include "afs_config.h"
16 #include "tab_prefs.h"
17 #include <hashlist.h>
18 #include <stdlib.h>
19
20
21 /*
22  * VARIABLES __________________________________________________________________
23  *
24  */
25
26 static struct l
27    {
28    CRITICAL_SECTION cs;
29    BOOL fThreadActive;
30    HWND hList;
31    } l;
32
33 #define cREALLOC_PREFS   32
34
35 #ifndef iswhite
36 #define iswhite(_ch) (((_ch)==TEXT(' ')) || ((_ch)==TEXT('\t')))
37 #endif
38 #ifndef iseol
39 #define iseol(_ch) (((_ch)==TEXT('\r')) || ((_ch)==TEXT('\n')))
40 #endif
41 #ifndef iswhiteeol
42 #define iswhiteeol(_ch) (iswhite(_ch) || iseol(_ch))
43 #endif
44
45
46 /*
47  * PROTOTYPES _________________________________________________________________
48  *
49  */
50
51 void PrefsTab_OnInitDialog (HWND hDlg);
52 BOOL PrefsTab_OnApply (HWND hDlg);
53 void PrefsTab_OnRefresh (HWND hDlg);
54 void PrefsTab_OnFillList (HWND hDlg);
55 void PrefsTab_OnSelect (HWND hDlg);
56 void PrefsTab_OnUpDown (HWND hDlg, BOOL fDown);
57 void PrefsTab_OnAdd (HWND hDlg);
58 void PrefsTab_OnEdit (HWND hDlg);
59 void PrefsTab_OnImport (HWND hDlg);
60
61 void PrefsTab_MergeServerPrefs (PSERVERPREFS pGlobal, PSERVERPREFS pAdd);
62 void PrefsTab_AddItem (HWND hDlg, PSERVERPREF pPref, BOOL fSelect);
63 void PrefsTab_AddItem (HWND hDlg, LPCTSTR pszServer, int iRank);
64
65 DWORD WINAPI PrefsTab_RefreshThread (PVOID lp);
66 DWORD WINAPI PrefsTab_ThreadProc (PVOID lp);
67 void PrefsTab_ThreadProcFunc (PSERVERPREFS pPrefs, BOOL *pfStopFlag);
68
69 int CALLBACK PrefsTab_SortFunction (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2);
70
71 BOOL CALLBACK IPKey_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData);
72 HASHVALUE CALLBACK IPKey_HashObject (LPHASHLISTKEY pKey, PVOID pObject);
73 HASHVALUE CALLBACK IPKey_HashData (LPHASHLISTKEY pKey, PVOID pData);
74
75 BOOL CALLBACK PrefsEdit_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
76 void PrefsEdit_OnInitDialog (HWND hDlg);
77 void PrefsEdit_OnOK (HWND hDlg);
78 void PrefsEdit_Enable (HWND hDlg);
79
80
81 /*
82  * ROUTINES ___________________________________________________________________
83  *
84  */
85
86 BOOL CALLBACK PrefsTab_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
87 {
88    switch (msg)
89       {
90       case WM_INITDIALOG:
91          InitializeCriticalSection (&l.cs);
92          PrefsTab_OnInitDialog (hDlg);
93          break;
94
95       case WM_COMMAND:
96          switch (LOWORD(wp))
97             {
98             case IDAPPLY:
99                if (!PrefsTab_OnApply (hDlg))
100                   SetWindowLong (hDlg, DWL_MSGRESULT, TRUE);
101                break;
102
103             case IDC_REFRESH:
104                PrefsTab_OnRefresh (hDlg);
105                break;
106
107             case IDC_SHOW_FS:
108             case IDC_SHOW_VLS:
109                PrefsTab_OnFillList (hDlg);
110                break;
111
112             case IDC_ADD:
113                PrefsTab_OnAdd (hDlg);
114                break;
115
116             case IDC_EDIT:
117                PrefsTab_OnEdit (hDlg);
118                break;
119
120             case IDC_UP:
121                PrefsTab_OnUpDown (hDlg, FALSE);
122                break;
123
124             case IDC_DOWN:
125                PrefsTab_OnUpDown (hDlg, TRUE);
126                break;
127
128             case IDC_IMPORT:
129                PrefsTab_OnImport (hDlg);
130                break;
131
132             case IDHELP:
133                PrefsTab_DlgProc (hDlg, WM_HELP, 0, 0);
134                break;
135             }
136          break;
137
138       case WM_HELP:
139          WinHelp (hDlg, g.szHelpFile, HELP_CONTEXT, IDH_AFSCONFIG_PREFS_NT);
140          break;
141
142       case WM_NOTIFY:
143          switch (((LPNMHDR)lp)->code)
144             {
145             case FLN_ITEMSELECT:
146                PrefsTab_OnSelect (hDlg);
147                break;
148
149             case FLN_LDBLCLICK:
150                if (IsWindowEnabled (GetDlgItem (hDlg, IDC_EDIT)))
151                   PrefsTab_OnEdit (hDlg);
152                break;
153             }
154          break;
155       }
156
157    return FALSE;
158 }
159
160
161 void PrefsTab_OnInitDialog (HWND hDlg)
162 {
163    HICON hiUp = TaLocale_LoadIcon (IDI_UP);
164    HICON hiDown = TaLocale_LoadIcon (IDI_DOWN);
165
166    SendDlgItemMessage (hDlg, IDC_UP, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hiUp);
167    SendDlgItemMessage (hDlg, IDC_DOWN, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hiDown);
168
169    CheckDlgButton (hDlg, IDC_SHOW_FS, TRUE);
170    CheckDlgButton (hDlg, IDC_SHOW_VLS, FALSE);
171
172    l.hList = GetDlgItem (hDlg, IDC_LIST);
173
174    FASTLISTCOLUMN Column;
175    Column.dwFlags = FLCF_JUSTIFY_LEFT;
176    Column.cxWidth = 200;
177    GetString (Column.szText, IDS_PREFCOL_SERVER);
178    FastList_SetColumn (l.hList, 0, &Column);
179
180    Column.dwFlags = FLCF_JUSTIFY_RIGHT;
181    Column.cxWidth = 40;
182    GetString (Column.szText, IDS_PREFCOL_RANK);
183    FastList_SetColumn (l.hList, 1, &Column);
184
185    FastList_SetSortFunction (l.hList, PrefsTab_SortFunction);
186
187    PrefsTab_OnFillList (hDlg);
188    PrefsTab_OnRefresh (hDlg);
189 }
190
191
192 BOOL PrefsTab_CommitChanges (BOOL fForce)
193 {
194    HWND hDlg;
195    if ((hDlg = PropSheet_FindTabWindow (g.psh, (DLGPROC)PrefsTab_DlgProc)) == NULL)
196       return TRUE;
197    if (fForce)
198       SetWindowLong (hDlg, DWL_MSGRESULT, FALSE); // Make sure we try to apply
199    if (PrefsTab_OnApply (hDlg))
200       return TRUE;
201    SetWindowLong (hDlg, DWL_MSGRESULT, TRUE);
202    return FALSE;
203 }
204
205
206 BOOL PrefsTab_OnApply (HWND hDlg)
207 {
208    // Don't try to do anything if we've already failed the apply
209    if (GetWindowLong (hDlg, DWL_MSGRESULT))
210       return FALSE;
211
212    if (g.Configuration.pFServers && g.Configuration.fChangedPrefs)
213       {
214       if (!Config_SetServerPrefs (g.Configuration.pFServers))
215          return FALSE;
216       }
217    if (g.Configuration.pVLServers && g.Configuration.fChangedPrefs)
218       {
219       if (!Config_SetServerPrefs (g.Configuration.pVLServers))
220          return FALSE;
221       }
222    g.Configuration.fChangedPrefs = FALSE;
223    return TRUE;
224 }
225
226
227 void PrefsTab_OnRefresh (HWND hDlg)
228 {
229    DWORD idThread;
230    CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)PrefsTab_RefreshThread, (PVOID)hDlg, 0, &idThread);
231 }
232
233
234 void PrefsTab_OnFillList (HWND hDlg)
235 {
236    EnterCriticalSection (&l.cs);
237    BOOL fVLServers = IsDlgButtonChecked (hDlg, IDC_SHOW_VLS);
238
239    // Empty the fastlist, and clear from the lists any mention of HLISTITEMs.
240    //
241    FastList_Begin (l.hList);
242    FastList_RemoveAll (l.hList);
243
244    if (g.Configuration.pVLServers)
245       {
246       for (size_t ii = 0; ii < g.Configuration.pVLServers->cPrefs; ++ii)
247          g.Configuration.pVLServers->aPrefs[ ii ].hItem = NULL;
248       }
249    if (g.Configuration.pFServers)
250       {
251       for (size_t ii = 0; ii < g.Configuration.pFServers->cPrefs; ++ii)
252          g.Configuration.pFServers->aPrefs[ ii ].hItem = NULL;
253       }
254
255    // Fill in the fastlist by adding entries from the appropriate prefslist.
256    //
257    PSERVERPREFS pPrefs = (fVLServers) ? g.Configuration.pVLServers : g.Configuration.pFServers;
258    if (pPrefs)
259       {
260       for (size_t ii = 0; ii < pPrefs->cPrefs; ++ii)
261          {
262          if (!pPrefs->aPrefs[ ii ].ipServer)
263             continue;
264
265          TCHAR szItem[ cchRESOURCE ];
266          if (!pPrefs->aPrefs[ ii ].szServer[0])
267             {
268             lstrcpy (szItem, inet_ntoa (*(struct in_addr *)&pPrefs->aPrefs[ ii ].ipServer));
269             }
270          else
271             {
272             wsprintf (szItem, TEXT("%s (%s)"),
273                       pPrefs->aPrefs[ ii ].szServer,
274                       inet_ntoa (*(struct in_addr *)&pPrefs->aPrefs[ ii ].ipServer));
275             }
276
277          FASTLISTADDITEM ai;
278          memset (&ai, 0x00, sizeof(FASTLISTADDITEM));
279          ai.iFirstImage = IMAGE_NOIMAGE;
280          ai.iSecondImage = IMAGE_NOIMAGE;
281          ai.pszText = szItem;
282          ai.lParam = ii;
283          pPrefs->aPrefs[ ii ].hItem = FastList_AddItem (l.hList, &ai);
284
285          wsprintf (szItem, TEXT("%ld"), pPrefs->aPrefs[ ii ].iRank);
286          FastList_SetItemText (l.hList, pPrefs->aPrefs[ ii ].hItem, 1, szItem);
287          }
288       }
289
290    // Okay, we're done!
291    //
292    FastList_End (l.hList);
293    LeaveCriticalSection (&l.cs);
294    PrefsTab_OnSelect (hDlg);
295 }
296
297
298 void PrefsTab_OnSelect (HWND hDlg)
299 {
300    if (IsWindowEnabled (l.hList))
301       {
302       HLISTITEM hItem = FastList_FindFirstSelected (l.hList);
303       HLISTITEM hItemFirst = FastList_FindFirst (l.hList);
304       HLISTITEM hItemNext = FastList_FindNext (l.hList, hItem);
305
306       EnableWindow (GetDlgItem (hDlg, IDC_UP), (hItem && (hItem != hItemFirst)));
307       EnableWindow (GetDlgItem (hDlg, IDC_DOWN), (hItem && hItemNext));
308       EnableWindow (GetDlgItem (hDlg, IDC_ADD), TRUE);
309       EnableWindow (GetDlgItem (hDlg, IDC_IMPORT), TRUE);
310       EnableWindow (GetDlgItem (hDlg, IDC_EDIT), !!hItem);
311       }
312 }
313
314
315 void PrefsTab_OnUpDown (HWND hDlg, BOOL fDown)
316 {
317    BOOL fVLServers = IsDlgButtonChecked (hDlg, IDC_SHOW_VLS);
318    PSERVERPREFS pPrefs = (fVLServers) ? g.Configuration.pVLServers : g.Configuration.pFServers;
319
320    HLISTITEM hItem;
321    if ((hItem = FastList_FindFirstSelected (l.hList)) == NULL)
322       return;
323
324    HLISTITEM hOther;
325    hOther = (fDown) ? FastList_FindNext(l.hList,hItem) : FastList_FindPrevious(l.hList,hItem);
326    if (hOther == NULL)
327       return;
328
329    size_t iItem = (size_t)FastList_GetItemParam (l.hList, hItem);
330    size_t iOther = (size_t)FastList_GetItemParam (l.hList, hOther);
331
332    if (!pPrefs || (pPrefs->cPrefs <= iItem) || (pPrefs->cPrefs <= iOther))
333       return;
334
335    FastList_Begin (l.hList);
336
337    PSERVERPREF pPref1 = &pPrefs->aPrefs[ iItem ];
338    PSERVERPREF pPref2 = &pPrefs->aPrefs[ iOther ];
339
340    if (pPref1->iRank == pPref2->iRank)
341       {
342       if (fDown && (pPref1->iRank < 65534))
343          pPref1->iRank ++;
344       else if ((!fDown) && (pPref1->iRank > 1))
345          pPref1->iRank --;
346       pPref1->fChanged = TRUE;
347       }
348    else // (pPref1->iRating != pPref2->iRating)
349       {
350       pPref1->iRank ^= pPref2->iRank;
351       pPref2->iRank ^= pPref1->iRank;
352       pPref1->iRank ^= pPref2->iRank;
353       pPref1->fChanged = TRUE;
354       pPref2->fChanged = TRUE;
355       }
356
357    TCHAR szText[ cchRESOURCE ];
358    wsprintf (szText, TEXT("%ld"), pPref1->iRank);
359    FastList_SetItemText (l.hList, pPref1->hItem, 1, szText);
360
361    wsprintf (szText, TEXT("%ld"), pPref2->iRank);
362    FastList_SetItemText (l.hList, pPref2->hItem, 1, szText);
363
364    FastList_EnsureVisible (l.hList, hItem);
365    FastList_End (l.hList);
366    PrefsTab_OnSelect (hDlg);
367
368    g.Configuration.fChangedPrefs = TRUE;
369 }
370
371
372 void PrefsTab_OnAdd (HWND hDlg)
373 {
374    BOOL fVLServers = IsDlgButtonChecked (hDlg, IDC_SHOW_VLS);
375    PSERVERPREFS pPrefs = (fVLServers) ? g.Configuration.pVLServers : g.Configuration.pFServers;
376
377    SERVERPREF Pref;
378    memset (&Pref, 0x00, sizeof(SERVERPREF));
379    Pref.iRank = 30000;
380
381    if (ModalDialogParam (IDD_PREFS_EDIT, GetParent(hDlg), (DLGPROC)PrefsEdit_DlgProc, (LPARAM)&Pref) == IDOK)
382       {
383       PrefsTab_AddItem (hDlg, &Pref, TRUE);
384       PrefsTab_OnSelect (hDlg);
385       g.Configuration.fChangedPrefs = TRUE;
386       }
387 }
388
389
390 void PrefsTab_OnEdit (HWND hDlg)
391 {
392    BOOL fVLServers = IsDlgButtonChecked (hDlg, IDC_SHOW_VLS);
393    PSERVERPREFS pPrefs = (fVLServers) ? g.Configuration.pVLServers : g.Configuration.pFServers;
394
395    HLISTITEM hItem;
396    if ((hItem = FastList_FindFirstSelected (l.hList)) == NULL)
397       return;
398
399    PSERVERPREF pPref = &pPrefs->aPrefs[ FastList_GetItemParam (l.hList, hItem) ];
400
401    if (ModalDialogParam (IDD_PREFS_EDIT, GetParent(hDlg), (DLGPROC)PrefsEdit_DlgProc, (LPARAM)pPref) == IDOK)
402       {
403       FastList_Begin (l.hList);
404
405       TCHAR szText[ cchRESOURCE ];
406       wsprintf (szText, TEXT("%ld"), pPref->iRank);
407       FastList_SetItemText (l.hList, pPref->hItem, 1, szText);
408       pPref->fChanged = TRUE;
409
410       FastList_EnsureVisible (l.hList, hItem);
411       FastList_End (l.hList);
412       PrefsTab_OnSelect (hDlg);
413       g.Configuration.fChangedPrefs = TRUE;
414       }
415 }
416
417
418 void PrefsTab_OnImport (HWND hDlg)
419 {
420    BOOL fVLServers = IsDlgButtonChecked (hDlg, IDC_SHOW_VLS);
421    PSERVERPREFS pPrefs = (fVLServers) ? g.Configuration.pVLServers : g.Configuration.pFServers;
422
423    TCHAR szFilename[ MAX_PATH ] = TEXT("");
424    if (Browse_Open (hDlg, szFilename, NULL, IDS_FILTER_TXT, 0, NULL, 0))
425       {
426       FastList_Begin (l.hList);
427
428       // Open the file and read it into memory.
429       //
430       HANDLE fh;
431       if ((fh = CreateFile (szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
432          {
433          DWORD cbLength = GetFileSize (fh, NULL);
434          LPTSTR pszBuffer = (LPTSTR)Allocate (sizeof(TCHAR) * (cbLength +2));
435
436          DWORD cbRead;
437          if (ReadFile (fh, pszBuffer, cbLength, &cbRead, NULL))
438             {
439             pszBuffer[ cbRead ] = TEXT('\0');
440             pszBuffer[ cbRead+1 ] = TEXT('\0');
441
442             // Scan the file line-by-line...
443             //
444             LPTSTR pszStart = pszBuffer;
445             while (pszStart && *pszStart)
446                {
447                while (iswhiteeol(*pszStart))
448                   ++pszStart;
449
450                LPTSTR pszEnd = pszStart;
451                while (*pszEnd && !iseol(*pszEnd))
452                   ++pszEnd;
453                *pszEnd++ = TEXT('\0');
454
455                // Okay, {pszStart} points to a 0-terminated line in this file.
456                // If the line starts with '#', ';' or '//', skip it.
457                //
458                if ( (pszStart[0] != TEXT('#')) &&
459                     (pszStart[0] != TEXT(';')) &&
460                    ((pszStart[0] != TEXT('/')) || (pszStart[1] != TEXT('/'))) )
461                   {
462                   // Break the line up into two sections: the machine name,
463                   // and the ranking.
464                   //
465                   TCHAR szServer[ MAX_PATH ];
466                   for (LPTSTR pszOut = szServer; *pszStart && !iswhite(*pszStart); )
467                      *pszOut++ = *pszStart++;
468                   *pszOut = TEXT('\0');
469
470                   while (iswhite(*pszStart))
471                      ++pszStart;
472
473                   TCHAR szRank[ MAX_PATH ];
474                   for (pszOut = szRank; *pszStart && !iswhite(*pszStart); )
475                      *pszOut++ = *pszStart++;
476                   *pszOut = TEXT('\0');
477
478                   PrefsTab_AddItem (hDlg, szServer, atoi(szRank));
479                   }
480
481                // Process the next line in the file.
482                //
483                pszStart = pszEnd;
484                }
485             }
486
487          Free (pszBuffer);
488          CloseHandle (fh);
489          }
490
491       // Restart the background thread, to resolve unknown IP address
492       //
493       PrefsTab_OnRefresh (hDlg);
494       FastList_End (l.hList);
495       g.Configuration.fChangedPrefs = TRUE;
496       }
497 }
498
499
500 void PrefsTab_MergeServerPrefs (PSERVERPREFS pGlobal, PSERVERPREFS pAdd)
501 {
502    LPHASHLIST pList = New (HASHLIST);
503    LPHASHLISTKEY pKey = pList->CreateKey (TEXT("IP Address"), IPKey_Compare, IPKey_HashObject, IPKey_HashData);
504
505    for (size_t ii = 0; ii < pGlobal->cPrefs; ++ii)
506       {
507       if (!pGlobal->aPrefs[ ii ].ipServer)
508          continue;
509       pList->Add (&pGlobal->aPrefs[ ii ]);
510       }
511
512    size_t iOut = 0;
513    for (ii = 0; ii < pAdd->cPrefs; ++ii)
514       {
515       if (!pAdd->aPrefs[ ii ].ipServer)
516          continue;
517
518       // The whole point of using a hashlist here is to allow this next call--
519       // on a hashlist, lookup and add are both constant-time, turning this
520       // merge into O(N) instead of (O(N^2))
521       //
522       if (pKey->GetFirstObject (&pAdd->aPrefs[ ii ].ipServer))
523          continue;
524
525       for ( ; iOut < pGlobal->cPrefs; ++iOut)
526          {
527          if (!pGlobal->aPrefs[ iOut ].ipServer)
528             break;
529          }
530
531       if (REALLOC (pGlobal->aPrefs, pGlobal->cPrefs, 1+iOut, cREALLOC_PREFS))
532          {
533          memcpy (&pGlobal->aPrefs[ iOut ], &pAdd->aPrefs[ ii ], sizeof(SERVERPREFS));
534          iOut++;
535          }
536       }
537
538    Delete (pList);
539 }
540
541
542 void PrefsTab_AddItem (HWND hDlg, PSERVERPREF pPref, BOOL fSelect)
543 {
544    BOOL fVLServers = IsDlgButtonChecked (hDlg, IDC_SHOW_VLS);
545    PSERVERPREFS pPrefs = (fVLServers) ? g.Configuration.pVLServers : g.Configuration.pFServers;
546
547    for (size_t ii = 0; ii < pPrefs->cPrefs; ++ii)
548       {
549       if (pPrefs->aPrefs[ ii ].ipServer == pPref->ipServer)
550          break;
551       }
552    if (ii == pPrefs->cPrefs)
553       {
554       for (ii = 0; ii < pPrefs->cPrefs; ++ii)
555          {
556          if (!pPrefs->aPrefs[ ii ].ipServer)
557             break;
558          }
559       if (!REALLOC (pPrefs->aPrefs, pPrefs->cPrefs, 1+ii, cREALLOC_PREFS))
560          return;
561       memcpy (&pPrefs->aPrefs[ ii ], pPref, sizeof(SERVERPREF));
562       }
563
564    FastList_Begin (l.hList);
565
566    if (!pPrefs->aPrefs[ ii ].hItem)
567       {
568       TCHAR szItem[ cchRESOURCE ];
569       if (!pPrefs->aPrefs[ ii ].szServer[0])
570          {
571          lstrcpy (szItem, inet_ntoa (*(struct in_addr *)&pPrefs->aPrefs[ ii ].ipServer));
572          }
573       else
574          {
575          wsprintf (szItem, TEXT("%s (%s)"),
576                    pPrefs->aPrefs[ ii ].szServer,
577                    inet_ntoa (*(struct in_addr *)&pPrefs->aPrefs[ ii ].ipServer));
578          }
579
580       FASTLISTADDITEM ai;
581       memset (&ai, 0x00, sizeof(FASTLISTADDITEM));
582       ai.iFirstImage = IMAGE_NOIMAGE;
583       ai.iSecondImage = IMAGE_NOIMAGE;
584       ai.pszText = szItem;
585       ai.lParam = ii;
586       pPrefs->aPrefs[ ii ].hItem = FastList_AddItem (l.hList, &ai);
587       }
588
589    TCHAR szText[ cchRESOURCE ];
590    wsprintf (szText, TEXT("%ld"), pPrefs->aPrefs[ ii ].iRank);
591    FastList_SetItemText (l.hList, pPrefs->aPrefs[ ii ].hItem, 1, szText);
592    pPrefs->aPrefs[ ii ].fChanged = TRUE;
593
594    FastList_End (l.hList);
595
596    if (fSelect)
597       {
598       FastList_SelectItem (l.hList, pPrefs->aPrefs[ ii ].hItem, TRUE);
599       FastList_SetFocus (l.hList, pPrefs->aPrefs[ ii ].hItem);
600       FastList_EnsureVisible (l.hList, pPrefs->aPrefs[ ii ].hItem);
601       PrefsTab_OnSelect (hDlg);
602       }
603 }
604
605
606 void PrefsTab_AddItem (HWND hDlg, LPCTSTR pszServer, int iRank)
607 {
608    if ((iRank < 1) || (iRank > 65534))
609       return;
610
611    SERVERPREF Pref;
612    memset (&Pref, 0x00, sizeof(SERVERPREF));
613    Pref.iRank = iRank;
614
615    // If the server's name is an IP address, we'll translate it later
616    // when we do them en masse.
617    //
618    if (isdigit (pszServer[0]))
619       {
620       if ((Pref.ipServer = inet_addr (pszServer)) == INADDR_NONE)
621          return;
622       }
623    else // (!isdigit (pszServer[0]))
624       {
625       HOSTENT *pEntry;
626       if ((pEntry = gethostbyname (pszServer)) != NULL)
627          {
628          lstrcpy (Pref.szServer, pEntry->h_name);
629          Pref.ipServer = *(int *)pEntry->h_addr;
630          }
631       }
632
633    PrefsTab_AddItem (hDlg, &Pref, FALSE);
634 }
635
636
637 DWORD WINAPI PrefsTab_RefreshThread (PVOID lp)
638 {
639    HWND hDlg = (HWND)lp;
640    static BOOL *pfStopFlag = NULL;
641
642    // We may have a background thread or two working on resolving IP addresses.
643    // Flag them to stop.
644    //
645    EnterCriticalSection (&l.cs);
646    if (l.fThreadActive)
647       {
648       if (pfStopFlag)
649          *pfStopFlag = FALSE;
650       }
651    pfStopFlag = NULL; // Thread will free this when it terminates
652
653    // Retrieve PSERVERPREFS structures, and merge them into our globals
654    //
655    PSERVERPREFS pVLServers = Config_GetServerPrefs (TRUE);
656    PSERVERPREFS pFServers = Config_GetServerPrefs (FALSE);
657
658    if (!g.Configuration.pVLServers)
659       g.Configuration.pVLServers = pVLServers;
660    else if (g.Configuration.pVLServers && pVLServers)
661       PrefsTab_MergeServerPrefs (g.Configuration.pVLServers, pVLServers);
662
663    if (!g.Configuration.pFServers)
664       g.Configuration.pFServers = pFServers;
665    else if (g.Configuration.pFServers && pFServers)
666       PrefsTab_MergeServerPrefs (g.Configuration.pFServers, pFServers);
667
668    // Add entries to the fastlist
669    //
670    PrefsTab_OnFillList (hDlg);
671
672    // Fire up a background thread to resolve IP addresses into server names
673    //
674    pfStopFlag = New (BOOL);
675    *pfStopFlag = FALSE;
676
677    DWORD idThread;
678    CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)PrefsTab_ThreadProc, (PVOID)pfStopFlag, 0, &idThread);
679    l.fThreadActive = TRUE;
680
681    // Enable or disable controls based on whether the service is running
682    //
683    BOOL fRunning = (Config_GetServiceState() == SERVICE_RUNNING) ? TRUE : FALSE;
684
685    EnableWindow (GetDlgItem (hDlg, IDC_SHOW_FS), fRunning);
686    EnableWindow (GetDlgItem (hDlg, IDC_SHOW_VLS), fRunning);
687    EnableWindow (GetDlgItem (hDlg, IDC_LIST), fRunning);
688    EnableWindow (GetDlgItem (hDlg, IDC_UP), fRunning);
689    EnableWindow (GetDlgItem (hDlg, IDC_DOWN), fRunning);
690    EnableWindow (GetDlgItem (hDlg, IDC_IMPORT), fRunning);
691    EnableWindow (GetDlgItem (hDlg, IDC_ADD), fRunning);
692    EnableWindow (GetDlgItem (hDlg, IDC_EDIT), fRunning);
693    PrefsTab_OnSelect (hDlg);
694
695    TCHAR szText[ cchRESOURCE ];
696    GetString (szText, (fRunning) ? IDS_TIP_PREFS : IDS_WARN_STOPPED);
697    SetDlgItemText (hDlg, IDC_WARN, szText);
698
699    // We're done!
700    //
701    LeaveCriticalSection (&l.cs);
702    return 0;
703 }
704
705
706 DWORD WINAPI PrefsTab_ThreadProc (PVOID lp)
707 {
708    BOOL *pfStopFlag = (BOOL*)lp;
709    if (pfStopFlag)
710       {
711       PrefsTab_ThreadProcFunc (g.Configuration.pFServers, pfStopFlag);
712       PrefsTab_ThreadProcFunc (g.Configuration.pVLServers, pfStopFlag);
713
714       l.fThreadActive = FALSE;
715       Delete (pfStopFlag);
716       }
717    return 0;
718 }
719
720
721 void PrefsTab_ThreadProcFunc (PSERVERPREFS pPrefs, BOOL *pfStopFlag)
722 {
723    for (size_t ii = 0; ; ++ii)
724       {
725       // Find the next IP address to translate
726       //
727       EnterCriticalSection (&l.cs);
728
729       if ( (*pfStopFlag) || (ii >= pPrefs->cPrefs) )
730          {
731          LeaveCriticalSection (&l.cs);
732          break;
733          }
734
735       int ipServer;
736       if ( ((ipServer = pPrefs->aPrefs[ ii ].ipServer) == 0) ||
737            (pPrefs->aPrefs[ ii ].szServer[0] != TEXT('\0')) )
738          {
739          LeaveCriticalSection (&l.cs);
740          continue;
741          }
742
743       LeaveCriticalSection (&l.cs);
744
745       // Translate this IP address into a name
746       //
747       HOSTENT *pEntry;
748       if ((pEntry = gethostbyaddr ((char*)&ipServer, sizeof(ipServer), AF_INET)) == NULL)
749          continue;
750
751       // Update the SERVERPREFS list, and if necessary, update the display
752       // to show the server's name
753       //
754       EnterCriticalSection (&l.cs);
755
756       if (!*pfStopFlag)
757          {
758          if ((ii < pPrefs->cPrefs) && (ipServer == pPrefs->aPrefs[ ii ].ipServer))
759             {
760             lstrcpy (pPrefs->aPrefs[ ii ].szServer, pEntry->h_name);
761             if (pPrefs->aPrefs[ ii ].szServer[0])
762                {
763                if (pPrefs->aPrefs[ ii ].hItem)
764                   {
765                   TCHAR szItem[ cchRESOURCE ];
766                   wsprintf (szItem, TEXT("%s (%s)"),
767                             pPrefs->aPrefs[ ii ].szServer,
768                             inet_ntoa (*(struct in_addr *)&pPrefs->aPrefs[ ii ].ipServer));
769
770                   FastList_SetItemText (l.hList, pPrefs->aPrefs[ ii ].hItem, 0, szItem);
771                   }
772                }
773             }
774          }
775
776       LeaveCriticalSection (&l.cs);
777       }
778 }
779
780
781 int CALLBACK PrefsTab_SortFunction (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
782 {
783    static PSERVERPREFS pPrefs = NULL;
784    if (!hItem1 || !hItem2)
785       {
786       BOOL fVLServers = IsDlgButtonChecked (GetParent(hList), IDC_SHOW_VLS);
787       pPrefs = (fVLServers) ? g.Configuration.pVLServers : g.Configuration.pFServers;
788       return 0;
789       }
790
791    if (!pPrefs || (pPrefs->cPrefs <= (size_t)lpItem1) || (pPrefs->cPrefs <= (size_t)lpItem2))
792       return 0;
793
794    PSERVERPREF pPref1 = &pPrefs->aPrefs[ lpItem1 ];
795    PSERVERPREF pPref2 = &pPrefs->aPrefs[ lpItem2 ];
796
797    if (pPref1->iRank != pPref2->iRank)
798       return pPref1->iRank - pPref2->iRank;
799
800    ULONG ip1 = (ULONG)htonl (pPref1->ipServer);
801    ULONG ip2 = (ULONG)htonl (pPref2->ipServer);
802    return (ip1 < ip2) ? -1 : 1;
803 }
804
805
806 BOOL CALLBACK IPKey_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
807 {
808    return (((PSERVERPREF)pObject)->ipServer == *(int*)pData);
809 }
810
811 HASHVALUE CALLBACK IPKey_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
812 {
813    return IPKey_HashData (pKey, &((PSERVERPREF)pObject)->ipServer);
814 }
815
816 HASHVALUE CALLBACK IPKey_HashData (LPHASHLISTKEY pKey, PVOID pData)
817 {
818    return *(int*)pData;
819 }
820
821
822 BOOL CALLBACK PrefsEdit_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
823 {
824    switch (msg)
825       {
826       case WM_INITDIALOG:
827          SetWindowLong (hDlg, DWL_USER, lp);
828          PrefsEdit_OnInitDialog (hDlg);
829          PrefsEdit_Enable (hDlg);
830          break;
831
832       case WM_COMMAND:
833          switch (LOWORD(wp))
834             {
835             case IDC_SERVER:
836                PrefsEdit_Enable (hDlg);
837                break;
838
839             case IDOK:
840                PrefsEdit_OnOK (hDlg);
841                break;
842
843             case IDCANCEL:
844                EndDialog (hDlg, IDCANCEL);
845                break;
846
847             case IDHELP:
848                PrefsEdit_DlgProc (hDlg, WM_HELP, 0, 0);
849                break;
850             }
851          break;
852
853       case WM_HELP:
854          WinHelp (hDlg, g.szHelpFile, HELP_CONTEXT, IDH_AFSCONFIG_PREFS_NT_ADDEDIT);
855          break;
856       }
857
858    return FALSE;
859 }
860
861
862 void PrefsEdit_OnInitDialog (HWND hDlg)
863 {
864    PSERVERPREF pPref = (PSERVERPREF)GetWindowLong (hDlg, DWL_USER);
865
866    if (pPref->ipServer)
867       EnableWindow (GetDlgItem (hDlg, IDC_SERVER), FALSE);
868
869    if (pPref->szServer[0])
870       {
871       SetDlgItemText (hDlg, IDC_SERVER, pPref->szServer);
872       }
873    else if (pPref->ipServer)
874       {
875       SetDlgItemText (hDlg, IDC_SERVER, inet_ntoa (*(struct in_addr *)&pPref->ipServer));
876       }
877
878    CreateSpinner (GetDlgItem (hDlg, IDC_RANK), 10, FALSE, 1, pPref->iRank, 65534);
879 }
880
881
882 void PrefsEdit_OnOK (HWND hDlg)
883 {
884    PSERVERPREF pPref = (PSERVERPREF)GetWindowLong (hDlg, DWL_USER);
885    pPref->iRank = SP_GetPos (GetDlgItem (hDlg, IDC_RANK));
886
887    if (IsWindowEnabled (GetDlgItem (hDlg, IDC_SERVER)))
888       {
889       BOOL rc = TRUE;
890       ULONG status = 0;
891
892       TCHAR szServer[ cchRESOURCE ];
893       GetDlgItemText (hDlg, IDC_SERVER, szServer, cchRESOURCE);
894       if (isdigit (szServer[0]))
895          {
896          if ((pPref->ipServer = inet_addr (szServer)) == INADDR_NONE)
897             {
898             rc = FALSE;
899             status = WSAGetLastError();
900             }
901          else
902             {
903             HOSTENT *pEntry;
904             if ((pEntry = gethostbyaddr ((char*)&pPref->ipServer, sizeof(pPref->ipServer), AF_INET)) != NULL)
905                lstrcpy (pPref->szServer, pEntry->h_name);
906             }
907          }
908       else // (!isdigit(pData->szServer[0]))
909          {
910          HOSTENT *pEntry;
911          if ((pEntry = gethostbyname (szServer)) == NULL)
912             {
913             rc = FALSE;
914             status = WSAGetLastError();
915             }
916          else
917             {
918             lstrcpy (pPref->szServer, pEntry->h_name);
919             pPref->ipServer = *(int *)pEntry->h_addr;
920             }
921          }
922
923       if (!rc)
924          {
925          Message (MB_ICONHAND | MB_OK, GetErrorTitle(), IDS_PREFERROR_RESOLVE, TEXT("%s%08lX"), szServer, status);
926          return;
927          }
928       }
929
930    EndDialog (hDlg, IDOK);
931 }
932
933
934 void PrefsEdit_Enable (HWND hDlg)
935 {
936    TCHAR szServer[ cchRESOURCE ];
937    GetDlgItemText (hDlg, IDC_SERVER, szServer, cchRESOURCE);
938
939    EnableWindow (GetDlgItem (hDlg, IDOK), !!szServer[0]);
940 }
941