windows-aklog-cleanup-20080321
[openafs.git] / src / WINNT / afssvrmgr / dispatch.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 #include <winsock2.h>
11 #include <ws2tcpip.h>
12
13 extern "C" {
14 #include <afs/param.h>
15 #include <afs/stds.h>
16 }
17
18 #include "svrmgr.h"
19 #include "dispatch.h"
20 #include "action.h"
21 #include "svr_general.h"
22 #include "svc_general.h"
23 #include "agg_general.h"
24 #include "set_general.h"
25 #include "subset.h"
26 #include "display.h"
27
28
29 /*
30  * DEFINITIONS ________________________________________________________________
31  *
32  */
33
34 #define cREALLOC_DISPATCH  32
35
36
37 /*
38  * VARIABLES __________________________________________________________________
39  *
40  */
41
42 static CRITICAL_SECTION csDispatch;
43
44 static LPNOTIFYCALLBACK Handler = NULL;
45
46 static struct
47    {
48    NOTIFYWHEN when;
49    LPIDENT lpiObject;
50    HWND hWnd;
51    LPARAM lpUser;
52    } *aDispatchList = NULL;
53
54 static size_t nDispatchList = 0;
55
56
57 typedef struct NOTIFYQUEUEITEM
58    {
59    struct NOTIFYQUEUEITEM *pNext;
60    NOTIFYEVENT evt;
61    NOTIFYPARAMS Params;
62    } NOTIFYQUEUEITEM, *LPNOTIFYQUEUEITEM;
63
64 static LPNOTIFYQUEUEITEM pDispatchQueuePop = NULL;
65 static LPNOTIFYQUEUEITEM pDispatchQueuePushAfter = NULL;
66
67
68 /*
69  * PROTOTYPES _________________________________________________________________
70  *
71  */
72
73 BOOL CALLBACK DispatchNotification (NOTIFYEVENT evt, PNOTIFYPARAMS pParams);
74
75 void DispatchNotification_AltThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams);
76
77 void DispatchNotification_MainThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams);
78
79
80 /*
81  * ROUTINES ___________________________________________________________________
82  *
83  */
84
85 void CreateNotificationDispatch (void)
86 {
87    InitializeCriticalSection (&csDispatch);
88
89    Handler = New2 (NOTIFYCALLBACK,((NOTIFYCALLBACKPROC)DispatchNotification, 0L));
90 }
91
92
93 void PostNotification (NOTIFYEVENT evt, LPIDENT lpi)
94 {
95    NOTIFYCALLBACK::SendNotificationToAll (evt, lpi);
96 }
97
98
99 /*
100  * DispatchNotification
101  *
102  * This routine is called by our NOTIFYCALLBACK object ("Handler") whenever
103  * anything interesting happens within the library.  Note that it's called
104  * on whatever thread the library is using--for that reason, we only handle
105  * some of the requests right away.  The rest get posted to our DispatchQueue,
106  * to be popped off by g.hMain's thread.
107  *
108  */
109
110 BOOL CALLBACK DispatchNotification (NOTIFYEVENT evt, PNOTIFYPARAMS pParams)
111 {
112    // Some things must be done right now--for instance, if we've just created
113    // or deleted a SERVER object, we'll load or free that server's preferences
114    // instantly.  So, give our on-alternate-thread handler a chance to
115    // look over the notification.
116    //
117    DispatchNotification_AltThread (evt, pParams);
118
119    // Then push this notification onto our DispatchQueue, so that the main
120    // pump will pop off each request in turn and take a look at it.
121    //
122    EnterCriticalSection (&csDispatch);
123
124    LPNOTIFYQUEUEITEM lpnqi = New (NOTIFYQUEUEITEM);
125    lpnqi->pNext = NULL;
126    lpnqi->evt = evt;
127    memcpy (&lpnqi->Params, pParams, sizeof(NOTIFYPARAMS));
128
129    if (pDispatchQueuePushAfter != NULL)
130       pDispatchQueuePushAfter->pNext = lpnqi;
131    pDispatchQueuePushAfter = lpnqi;
132
133    if (pDispatchQueuePop == NULL)
134       pDispatchQueuePop = lpnqi;
135
136    LeaveCriticalSection (&csDispatch);
137
138    return TRUE;
139 }
140
141
142 void DispatchNotification_OnPump (void)
143 {
144    BOOL fFound = TRUE;
145
146    do {
147       NOTIFYQUEUEITEM nqi;
148
149       EnterCriticalSection (&csDispatch);
150
151       if (!pDispatchQueuePop)
152          fFound = FALSE;
153       else
154          {
155          LPNOTIFYQUEUEITEM lpnqiNext = pDispatchQueuePop->pNext;
156          memcpy (&nqi, pDispatchQueuePop, sizeof(NOTIFYQUEUEITEM));
157
158          if (pDispatchQueuePushAfter == pDispatchQueuePop)
159             pDispatchQueuePushAfter = NULL;
160          Delete (pDispatchQueuePop);
161          pDispatchQueuePop = lpnqiNext;
162          }
163
164       LeaveCriticalSection (&csDispatch);
165
166       if (fFound)
167          {
168          DispatchNotification_MainThread (nqi.evt, &nqi.Params);
169          }
170       } while (fFound);
171 }
172
173
174 void DispatchNotification_AltThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams)
175 {
176    LPIDENT lpiEvt = pParams->lpi1;
177
178    switch (evt)
179       {
180       case evtRefreshStatusEnd:
181          if (lpiEvt && (lpiEvt->fIsService() || lpiEvt->fIsAggregate() || lpiEvt->fIsFileset()))
182             {
183             Alert_RemoveSecondary (lpiEvt);
184             Alert_Scout_QueueCheckServer (lpiEvt);
185             }
186          if (lpiEvt && lpiEvt->fIsServer())
187             {
188             LPSERVER_PREF lpsp;
189             if ((lpsp = (LPSERVER_PREF)lpiEvt->GetUserParam()) != NULL)
190                {
191                LPSERVER lpServer;
192                if ((lpServer = lpiEvt->OpenServer()) != NULL)
193                   {
194                   if (lpsp->fIsMonitored != lpServer->fIsMonitored())
195                      {
196                      g.sub = Subsets_SetMonitor (g.sub, lpiEvt, lpServer->fIsMonitored());
197                      UpdateDisplay_ServerWindow (FALSE, lpiEvt);
198                      }
199                   lpsp->fIsMonitored = lpServer->fIsMonitored();
200                   lpServer->Close();
201                   }
202                }
203
204             Alert_Scout_ServerStatus (lpiEvt, pParams->status);
205             }
206          break;
207
208       // When we get a create request, use the object's Get/SetUserParam()
209       // methods to attach an allocated structure to the thing--the structure
210       // contains the preferences for the server/fileset/etc (for instance,
211       // its warning threshholds, any current scout problems, etc).
212       // On delete requests, free that structure.
213       //
214       case evtCreate:
215          if (lpiEvt->fIsServer())
216             {
217             PVOID pPref = Server_LoadPreferences (lpiEvt);
218             lpiEvt->SetUserParam (pPref);
219
220             // Should this server be monitored?
221             //
222             if (!Subsets_fMonitorServer (g.sub, lpiEvt))
223                {
224                LPSERVER lpServer;
225                if ((lpServer = lpiEvt->OpenServer()) != NULL)
226                   {
227                   lpServer->SetMonitor (FALSE);
228                   lpServer->Close();
229                   }
230                }
231
232             Alert_Scout_SetOutOfDate (lpiEvt);
233             }
234          else if (lpiEvt->fIsService())
235             {
236             PVOID pPref = Services_LoadPreferences (lpiEvt);
237             lpiEvt->SetUserParam (pPref);
238             }
239          else if (lpiEvt->fIsAggregate())
240             {
241             PVOID pPref = Aggregates_LoadPreferences (lpiEvt);
242             lpiEvt->SetUserParam (pPref);
243             }
244          else if (lpiEvt->fIsFileset())
245             {
246             PVOID pPref = Filesets_LoadPreferences (lpiEvt);
247             lpiEvt->SetUserParam (pPref);
248             }
249          if (!lpiEvt->fIsCell())
250             {
251             Alert_Scout_QueueCheckServer (lpiEvt);
252             }
253          break;
254
255       // When we get a create request, use the object's Get/SetUserParam()
256       // methods to attach an allocated structure to the thing--the structure
257       // contains the preferences for the server/fileset/etc (for instance,
258       // its warning threshholds, any current scout problems, etc).
259       // On delete requests, free that structure.
260       //
261       case evtDestroy:
262          if (lpiEvt->fIsServer())
263             {
264             PVOID pPref = lpiEvt->GetUserParam();
265             lpiEvt->SetUserParam (0);
266             if (pPref)  Delete (pPref);
267             }
268          else if (lpiEvt->fIsService() || lpiEvt->fIsAggregate() || lpiEvt->fIsFileset())
269             {
270             Alert_RemoveSecondary (lpiEvt);
271             PVOID pPref = lpiEvt->GetUserParam();
272             lpiEvt->SetUserParam (0);
273             if (pPref)  Delete (pPref);
274             }
275          break;
276       }
277 }
278
279
280 void DispatchNotification_MainThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams)
281 {
282    LPIDENT lpiEvt = pParams->lpi1;
283
284    // There are several notifications which are sent when beginning or ending
285    // lengthy operations.  These "actions" each get a window indicating
286    // progress, and get added to our ongoing list of actions-in-progress.
287    //
288    ActionNotification_MainThread (evt, pParams);
289
290    // The real reason for this routine is as a dispatcher for the AFSClass's
291    // notifications: various windows throughout the app register themselves
292    // with this dispatcher, and thereby get a message whenever a particular
293    // event of interest to that window happens.  Just what notifications
294    // are "of interest" is specified by the window when it registers with
295    // this dispatcher.
296    //
297    for (size_t iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
298       {
299       if (!aDispatchList[ iDispatch ].hWnd)
300          continue;
301
302       BOOL fDispatch = FALSE;
303
304       // WHEN_CELL_OPENED + NULL      -> notify if any new cell is opened
305       // WHEN_OBJECT_CHANGES + NULL   -> notify if anything at all changes
306       // WHEN_OBJECT_CHANGES + lpi    -> notify if this object changes
307       // WHEN_SVCS(etc)_CHANGE + NULL -> notify if any service at all changes
308       // WHEN_SVCS(etc)_CHANGE + lpi  -> notify if any svc on this svr changes
309
310       switch (aDispatchList[ iDispatch ].when)
311          {
312          case WHEN_CELL_OPENED:
313             if (evt == evtCreate && lpiEvt->fIsCell())
314                fDispatch = TRUE;
315             break;
316
317          case WHEN_OBJECT_CHANGES:
318             if ( (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
319                  (aDispatchList[ iDispatch ].lpiObject == NULL) )
320                {
321                if (evt != evtCreate)
322                   fDispatch = TRUE;
323                }
324             break;
325
326          case WHEN_SVRS_CHANGE:
327             switch (evt)
328                {
329                case evtInvalidate:
330                case evtRefreshServersBegin:
331                case evtRefreshServersEnd:
332                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
333                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
334                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
335                      {
336                      if (lpiEvt && lpiEvt->fIsCell())
337                         fDispatch = TRUE;
338                      }
339                   break;
340
341                case evtCreate:
342                case evtDestroy:
343                case evtRefreshStatusBegin:
344                case evtRefreshStatusEnd:
345                case evtAlertsChanged:
346                   if (lpiEvt && lpiEvt->fIsServer())
347                      {
348                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
349                         fDispatch = TRUE;
350                      else
351                         {
352                         LPIDENT lpiEvtCell = lpiEvt->GetCell();
353
354                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtCell)
355                            fDispatch = TRUE;
356                         }
357                      }
358                   break;
359                }
360             break;
361
362          case WHEN_SETS_CHANGE:
363             switch (evt)
364                {
365                case evtInvalidate:
366                case evtRefreshFilesetsBegin:
367                case evtRefreshFilesetsEnd:
368                   {
369                   LPIDENT lpiEvtSvr = NULL;
370                   if (lpiEvt && !lpiEvt->fIsCell())
371                      lpiEvtSvr = lpiEvt->GetServer();
372
373                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
374                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt)    ||
375                        (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr) ||
376                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
377                      {
378                      if (lpiEvt && (lpiEvt->fIsCell() || lpiEvt->fIsServer() || lpiEvt->fIsAggregate()))
379                         fDispatch = TRUE;
380                      }
381                   }
382                   break;
383
384                case evtCreate:
385                case evtDestroy:
386                case evtRefreshStatusBegin:
387                case evtRefreshStatusEnd:
388                case evtAlertsChanged:
389                   if (lpiEvt && lpiEvt->fIsFileset())
390                      {
391                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
392                         fDispatch = TRUE;
393                      else
394                         {
395                         LPIDENT lpiEvtAgg = lpiEvt->GetAggregate();
396                         LPIDENT lpiEvtSvr = lpiEvt->GetServer();
397
398                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtAgg)
399                            fDispatch = TRUE;
400                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr)
401                            fDispatch = TRUE;
402                         }
403                      }
404                   break;
405                }
406             break;
407
408          case WHEN_AGGS_CHANGE:
409             switch (evt)
410                {
411                case evtRefreshAggregatesBegin:
412                case evtRefreshAggregatesEnd:
413                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
414                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
415                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
416                      {
417                      if (lpiEvt && (lpiEvt->fIsCell() || lpiEvt->fIsServer()))
418                         fDispatch = TRUE;
419                      }
420                   break;
421
422                case evtCreate:
423                case evtDestroy:
424                case evtRefreshStatusBegin:
425                case evtRefreshStatusEnd:
426                case evtAlertsChanged:
427                   if (lpiEvt && lpiEvt->fIsAggregate())
428                      {
429                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
430                         fDispatch = TRUE;
431                      else
432                         {
433                         LPIDENT lpiEvtSvr = lpiEvt->GetServer();
434
435                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr)
436                            fDispatch = TRUE;
437                         }
438                      }
439                   break;
440                }
441             break;
442
443          case WHEN_SVCS_CHANGE:
444             switch (evt)
445                {
446                case evtRefreshServicesBegin:
447                case evtRefreshServicesEnd:
448                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
449                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
450                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
451                      {
452                      if (lpiEvt && (lpiEvt->fIsCell() || lpiEvt->fIsServer()))
453                         fDispatch = TRUE;
454                      }
455                   break;
456
457                case evtCreate:
458                case evtDestroy:
459                case evtRefreshStatusBegin:
460                case evtRefreshStatusEnd:
461                case evtAlertsChanged:
462                   if (lpiEvt && lpiEvt->fIsService())
463                      {
464                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
465                         fDispatch = TRUE;
466                      else
467                         {
468                         LPIDENT lpiEvtSvr = lpiEvt->GetServer();
469
470                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr)
471                            fDispatch = TRUE;
472                         }
473                      }
474                   break;
475                }
476             break;
477          }
478
479       if (fDispatch)
480          {
481          LPNOTIFYSTRUCT lpns = New (NOTIFYSTRUCT);
482          lpns->hwndTarget = aDispatchList[ iDispatch ].hWnd;
483          lpns->evt = evt;
484          memcpy (&lpns->Params, pParams, sizeof(NOTIFYPARAMS));
485          lpns->Params.lpUser = aDispatchList[ iDispatch ].lpUser;
486
487          PostMessage (aDispatchList[ iDispatch ].hWnd,
488                       WM_NOTIFY_FROM_DISPATCH,
489                       (WPARAM)0,
490                       (LPARAM)lpns);
491          }
492       }
493 }
494
495
496 void NotifyMe (NOTIFYWHEN when, LPIDENT lpiObject, HWND hWnd, LPARAM lpUser)
497 {
498    EnterCriticalSection (&csDispatch);
499
500    size_t iDispatch;
501    for (iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
502       {
503       if ( (aDispatchList[ iDispatch ].hWnd == hWnd) &&
504            (aDispatchList[ iDispatch ].when == when) &&
505            (aDispatchList[ iDispatch ].lpiObject == lpiObject) )
506          {
507          LeaveCriticalSection (&csDispatch);
508          return;
509          }
510       }
511
512    for (iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
513       {
514       if (!aDispatchList[ iDispatch ].hWnd)
515          break;
516       }
517
518    if (iDispatch >= nDispatchList)
519       {
520       if (!REALLOC (aDispatchList, nDispatchList, 1+iDispatch, cREALLOC_DISPATCH))
521          {
522          LeaveCriticalSection (&csDispatch);
523          return;
524          }
525       }
526
527    aDispatchList[ iDispatch ].hWnd = hWnd;
528    aDispatchList[ iDispatch ].when = when;
529    aDispatchList[ iDispatch ].lpiObject = lpiObject;
530    aDispatchList[ iDispatch ].lpUser = lpUser;
531
532    LeaveCriticalSection (&csDispatch);
533 }
534
535
536 void DontNotifyMe (NOTIFYWHEN when, LPIDENT lpiObject, HWND hWnd)
537 {
538    EnterCriticalSection (&csDispatch);
539
540    for (size_t iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
541       {
542       if ( (aDispatchList[ iDispatch ].hWnd == hWnd) &&
543            (aDispatchList[ iDispatch ].when == when) &&
544            (aDispatchList[ iDispatch ].lpiObject == lpiObject) )
545          {
546          aDispatchList[ iDispatch ].hWnd = NULL;
547          }
548       }
549
550    LeaveCriticalSection (&csDispatch);
551 }
552
553
554 void DontNotifyMeEver (HWND hWnd)
555 {
556    EnterCriticalSection (&csDispatch);
557
558    for (size_t iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
559       {
560       if (aDispatchList[ iDispatch ].hWnd == hWnd)
561          {
562          aDispatchList[ iDispatch ].hWnd = NULL;
563          }
564       }
565
566    LeaveCriticalSection (&csDispatch);
567 }
568