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