]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/sysman.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / scheduler / sysman.c
index 6267b665bfdff947e1c4175e28bde86d32da2849..9f0319a62720badd49d6a3905cc10b568e5e55b6 100644 (file)
@@ -1,37 +1,14 @@
 /*
- * "$Id: sysman.c 6291 2007-02-19 21:54:27Z mike $"
+ * System management functions for the CUPS scheduler.
  *
- *   System management definitions for the Common UNIX Printing System (CUPS).
+ * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
  *
- *   Copyright 2006 by Easy Software Products.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
- *
- * Contents:
- *
- *   cupsdStartSystemMonitor()       - Start monitoring for system change.
- *   cupsdStopSystemMonitor()        - Stop monitoring for system change.
- *   cupsdUpdateSystemMonitor()      - Update the current system state.
- *   sysEventThreadEntry()           - A thread to receive power and computer
- *                                     name change notifications.
- *   sysEventPowerNotifier()         - Handle power notification events.
- *   sysEventConfigurationNotifier() - Computer name changed notification
- *                                     callback.
- *   sysEventTimerNotifier()         - Handle delayed event notifications.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file.  If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
  */
 
 
  */
 
 #include "cupsd.h"
+#ifdef __APPLE__
+#  include <vproc.h>
+#  include <IOKit/pwr_mgt/IOPMLib.h>
+#endif /* __APPLE__ */
 
 
 /*
- * Power management is a new addition to CUPS.  Right now it is only
- * implemented on MacOS X, but essentially we use these three functions
- * to let the OS know when it is OK to put the system to sleep, typically
- * when we are not in the middle of printing a job.
+ * The system management functions cover disk and power management which
+ * are primarily used for portable computers.
+ *
+ * Disk management involves delaying the write of certain configuration
+ * and state files to minimize the number of times the disk has to spin
+ * up or flash to be written to.
  *
- * Once put to sleep, we invalidate all remote printers since it is
- * common to wake up in a new location.
+ * Power management support is currently only implemented on OS X, but
+ * essentially we use four functions to let the OS know when it is OK to
+ * put the system to sleep, typically when we are not in the middle of
+ * printing a job.  And on OS X we can also "sleep print" - basically the
+ * system only wakes up long enough to service network requests and process
+ * print jobs.
+ */
+
+
+/*
+ * 'cupsdCleanDirty()' - Write dirty config and state files.
+ */
+
+void
+cupsdCleanDirty(void)
+{
+  if (DirtyFiles & CUPSD_DIRTY_PRINTERS)
+    cupsdSaveAllPrinters();
+
+  if (DirtyFiles & CUPSD_DIRTY_CLASSES)
+    cupsdSaveAllClasses();
+
+  if (DirtyFiles & CUPSD_DIRTY_PRINTCAP)
+    cupsdWritePrintcap();
+
+  if (DirtyFiles & CUPSD_DIRTY_JOBS)
+  {
+    cupsd_job_t        *job;                   /* Current job */
+
+    cupsdSaveAllJobs();
+
+    for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+         job;
+        job = (cupsd_job_t *)cupsArrayNext(Jobs))
+      if (job->dirty)
+        cupsdSaveJob(job);
+  }
+
+  if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS)
+    cupsdSaveAllSubscriptions();
+
+  DirtyFiles     = CUPSD_DIRTY_NONE;
+  DirtyCleanTime = 0;
+
+  cupsdSetBusyState();
+}
+
+
+/*
+ * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
  */
 
+void
+cupsdMarkDirty(int what)               /* I - What file(s) are dirty? */
+{
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMarkDirty(%c%c%c%c%c)",
+                 (what & CUPSD_DIRTY_PRINTERS) ? 'P' : '-',
+                 (what & CUPSD_DIRTY_CLASSES) ? 'C' : '-',
+                 (what & CUPSD_DIRTY_PRINTCAP) ? 'p' : '-',
+                 (what & CUPSD_DIRTY_JOBS) ? 'J' : '-',
+                 (what & CUPSD_DIRTY_SUBSCRIPTIONS) ? 'S' : '-');
+
+  if (what == CUPSD_DIRTY_PRINTCAP && !Printcap)
+    return;
+
+  DirtyFiles |= what;
+
+  if (!DirtyCleanTime)
+    DirtyCleanTime = time(NULL) + DirtyCleanInterval;
+
+  cupsdSetBusyState();
+}
+
+
+/*
+ * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
+ */
+
+void
+cupsdSetBusyState(void)
+{
+  int                  i;              /* Looping var */
+  cupsd_job_t          *job;           /* Current job */
+  cupsd_printer_t      *p;             /* Current printer */
+  int                  newbusy;        /* New busy state */
+  static int           busy = 0;       /* Current busy state */
+  static const char * const busy_text[] =
+  {                                    /* Text for busy states */
+    "Not busy",
+    "Dirty files",
+    "Printing jobs",
+    "Printing jobs and dirty files",
+    "Active clients",
+    "Active clients and dirty files",
+    "Active clients and printing jobs",
+    "Active clients, printing jobs, and dirty files"
+  };
+#ifdef __APPLE__
+  static vproc_transaction_t vtran = 0;        /* Current busy transaction */
+  static IOPMAssertionID keep_awake = 0;/* Keep the system awake while printing */
+#endif /* __APPLE__ */
+
+
+ /*
+  * Figure out how busy we are...
+  */
+
+  newbusy = (DirtyCleanTime ? 1 : 0) |
+           (cupsArrayCount(ActiveClients) ? 4 : 0);
+
+  for (job = (cupsd_job_t *)cupsArrayFirst(PrintingJobs);
+       job;
+       job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
+  {
+    if ((p = job->printer) != NULL)
+    {
+      for (i = 0; i < p->num_reasons; i ++)
+       if (!strcmp(p->reasons[i], "connecting-to-device"))
+         break;
+
+      if (!p->num_reasons || i >= p->num_reasons)
+       break;
+    }
+  }
+
+  if (job)
+    newbusy |= 2;
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG,
+                  "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
+                  busy_text[newbusy], busy_text[busy]);
+
+ /*
+  * Manage state changes...
+  */
+
+  if (newbusy != busy)
+  {
+    busy = newbusy;
+
+#ifdef __APPLE__
+    if (busy && !vtran)
+      vtran = vproc_transaction_begin(NULL);
+    else if (!busy && vtran)
+    {
+      vproc_transaction_end(NULL, vtran);
+      vtran = 0;
+    }
+#endif /* __APPLE__ */
+  }
+
+#ifdef __APPLE__
+  if (cupsArrayCount(PrintingJobs) > 0 && !keep_awake)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "Asserting NetworkClientActive.");
+
+    IOPMAssertionCreateWithName(kIOPMAssertNetworkClientActive,
+                               kIOPMAssertionLevelOn,
+                               CFSTR("org.cups.cupsd"), &keep_awake);
+  }
+  else if (cupsArrayCount(PrintingJobs) == 0 && keep_awake)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "Releasing power assertion.");
+    IOPMAssertionRelease(keep_awake);
+    keep_awake = 0;
+  }
+#endif /* __APPLE__ */
+}
+
+
 #ifdef __APPLE__
 /*
  * This is the Apple-specific system event code.  It works by creating
  * Include MacOS-specific headers...
  */
 
+#  include <notify.h>
 #  include <IOKit/IOKitLib.h>
 #  include <IOKit/IOMessage.h>
+#  include <IOKit/ps/IOPowerSources.h>
 #  include <IOKit/pwr_mgt/IOPMLib.h>
 #  include <SystemConfiguration/SystemConfiguration.h>
 #  include <pthread.h>
 #  define SYSEVENT_NAMECHANGED 0x10    /* Computer name changed */
 
 
-/* 
- * Structures... 
+/*
+ * Structures...
  */
 
 typedef struct cupsd_sysevent_s                /*** System event data ****/
@@ -101,20 +252,21 @@ typedef struct cupsd_thread_data_s        /*** Thread context data  ****/
 } cupsd_thread_data_t;
 
 
-/* 
- * Local globals... 
+/*
+ * Local globals...
  */
 
 static pthread_t       SysEventThread = NULL;
                                        /* Thread to host a runloop */
 static pthread_mutex_t SysEventThreadMutex = { 0 };
-                                       /* Coordinates access to shared gloabals */ 
+                                       /* Coordinates access to shared gloabals */
 static pthread_cond_t  SysEventThreadCond = { 0 };
                                        /* Thread initialization complete condition */
 static CFRunLoopRef    SysEventRunloop = NULL;
                                        /* The runloop. Access must be protected! */
 static CFStringRef     ComputerNameKey = NULL,
                                        /* Computer name key */
+                       BTMMKey = NULL, /* Back to My Mac key */
                        NetworkGlobalKeyIPv4 = NULL,
                                        /* Network global IPv4 key */
                        NetworkGlobalKeyIPv6 = NULL,
@@ -127,10 +279,13 @@ static CFStringRef        ComputerNameKey = NULL,
                                        /* Netowrk interface key */
                        NetworkInterfaceKeyIPv6 = NULL;
                                        /* Netowrk interface key */
+static cupsd_sysevent_t        LastSysEvent;   /* Last system event (for delayed sleep) */
+static int             NameChanged = 0;/* Did we get a 'name changed' event during sleep? */
+static int             PSToken = 0;    /* Power source notifications */
 
 
-/* 
- * Local functions... 
+/*
+ * Local functions...
  */
 
 static void    *sysEventThreadEntry(void);
@@ -141,6 +296,23 @@ static void        sysEventConfigurationNotifier(SCDynamicStoreRef store,
                                              CFArrayRef changedKeys,
                                              void *context);
 static void    sysEventTimerNotifier(CFRunLoopTimerRef timer, void *context);
+static void    sysUpdate(void);
+static void    sysUpdateNames(void);
+
+
+/*
+ * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
+ */
+
+void
+cupsdAllowSleep(void)
+{
+  cupsdCleanDirty();
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
+  IOAllowPowerChange(LastSysEvent.powerKernelPort,
+                    LastSysEvent.powerNotificationID);
+}
 
 
 /*
@@ -153,6 +325,8 @@ cupsdStartSystemMonitor(void)
   int  flags;                          /* fcntl flags on pipe */
 
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartSystemMonitor()");
+
   if (cupsdOpenPipe(SysEventPipes))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, "System event monitor pipe() failed - %s!",
@@ -160,8 +334,7 @@ cupsdStartSystemMonitor(void)
     return;
   }
 
-  cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)cupsdUpdateSystemMonitor,
-                 NULL, NULL);
+  cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)sysUpdate, NULL, NULL);
 
  /*
   * Set non-blocking mode on the descriptor we will be receiving notification
@@ -178,6 +351,15 @@ cupsdStartSystemMonitor(void)
   pthread_mutex_init(&SysEventThreadMutex, NULL);
   pthread_cond_init(&SysEventThreadCond, NULL);
   pthread_create(&SysEventThread, NULL, (void *(*)())sysEventThreadEntry, NULL);
+
+ /*
+  * Monitor for power source changes via dispatch queue...
+  */
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartSystemMonitor: IOPSGetTimeRemainingEstimate=%f", IOPSGetTimeRemainingEstimate());
+  ACPower = IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited;
+  notify_register_dispatch(kIOPSNotifyPowerSource, &PSToken, dispatch_get_main_queue(), ^(int t) { (void)t;
+      ACPower = IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited; });
 }
 
 
@@ -191,6 +373,8 @@ cupsdStopSystemMonitor(void)
   CFRunLoopRef rl;                     /* The event handler runloop */
 
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopSystemMonitor()");
+
   if (SysEventThread)
   {
    /*
@@ -221,166 +405,11 @@ cupsdStopSystemMonitor(void)
     cupsdRemoveSelect(SysEventPipes[0]);
     cupsdClosePipe(SysEventPipes);
   }
-}
-
 
-/*
- * 'cupsdUpdateSystemMonitor()' - Update the current system state.
- */
-
-void
-cupsdUpdateSystemMonitor(void)
-{
-  int                  i;              /* Looping var */
-  cupsd_sysevent_t     sysevent;       /* The system event */
-  cupsd_printer_t      *p;             /* Printer information */
-
-
- /*
-  * Drain the event pipe...
-  */
-
-  while (read((int)SysEventPipes[0], &sysevent, sizeof(sysevent))
-             == sizeof(sysevent))
+  if (PSToken != 0)
   {
-    if (sysevent.event & SYSEVENT_CANSLEEP)
-    {
-     /*
-      * If there are active printers that don't have the connecting-to-device
-      * printer-state-reason then cancel the sleep request (i.e. this reason
-      * indicates a job that is not yet connected to the printer)...
-      */
-
-      for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-           p;
-          p = (cupsd_printer_t *)cupsArrayNext(Printers))
-      {
-        if (p->job)
-        {
-         for (i = 0; i < p->num_reasons; i ++)
-           if (!strcmp(p->reasons[i], "connecting-to-device"))
-             break;
-
-         if (!p->num_reasons || i >= p->num_reasons)
-           break;
-        }
-      }
-
-      if (p)
-      {
-        cupsdLogMessage(CUPSD_LOG_INFO,
-                       "System sleep canceled because printer %s is active",
-                       p->name);
-        IOCancelPowerChange(sysevent.powerKernelPort,
-                           sysevent.powerNotificationID);
-      }
-      else
-      {
-       cupsdLogMessage(CUPSD_LOG_DEBUG, "System wants to sleep");
-        IOAllowPowerChange(sysevent.powerKernelPort,
-                          sysevent.powerNotificationID);
-      }
-    }
-
-    if (sysevent.event & SYSEVENT_WILLSLEEP)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "System going to sleep");
-
-      Sleeping = 1;
-
-      cupsdStopAllJobs(0);
-      cupsdSaveAllJobs();
-
-      for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-           p;
-          p = (cupsd_printer_t *)cupsArrayNext(Printers))
-      {
-       if (p->type & CUPS_PRINTER_REMOTE)
-       {
-         cupsdLogMessage(CUPSD_LOG_DEBUG,
-                         "Deleting remote destination \"%s\"", p->name);
-         cupsArraySave(Printers);
-         cupsdDeletePrinter(p, 0);
-         cupsArrayRestore(Printers);
-       }
-       else
-       {
-         cupsdLogMessage(CUPSD_LOG_DEBUG,
-                         "Deregistering local printer \"%s\"", p->name);
-         cupsdDeregisterPrinter(p, 0);
-       }
-      }
-
-      IOAllowPowerChange(sysevent.powerKernelPort,
-                         sysevent.powerNotificationID);
-    }
-
-    if (sysevent.event & SYSEVENT_WOKE)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "System woke from sleep");
-      IOAllowPowerChange(sysevent.powerKernelPort,
-                         sysevent.powerNotificationID);
-      Sleeping = 0;
-      cupsdCheckJobs();
-    }
-
-    if (sysevent.event & SYSEVENT_NETCHANGED)
-    {
-      if (!Sleeping)
-      {
-        cupsdLogMessage(CUPSD_LOG_DEBUG,
-                       "System network configuration changed");
-
-       /*
-        * Resetting browse_time before calling cupsdSendBrowseList causes
-       * browse packets to be sent for local shared printers.
-        */
-
-       for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-            p;
-            p = (cupsd_printer_t *)cupsArrayNext(Printers))
-         p->browse_time = 0;
-
-        cupsdSendBrowseList();
-       cupsdRestartPolling();
-      }
-      else
-        cupsdLogMessage(CUPSD_LOG_DEBUG,
-                       "System network configuration changed; "
-                       "ignored while sleeping");
-    }
-
-    if (sysevent.event & SYSEVENT_NAMECHANGED)
-    {
-      if (!Sleeping)
-      {
-        cupsdLogMessage(CUPSD_LOG_DEBUG, "Computer name changed");
-
-       /*
-       * De-register the individual printers...
-       */
-
-       for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-            p;
-            p = (cupsd_printer_t *)cupsArrayNext(Printers))
-         cupsdDeregisterPrinter(p, 1);
-
-       /*
-       * Now re-register them...
-       */
-
-       for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-            p;
-            p = (cupsd_printer_t *)cupsArrayNext(Printers))
-       {
-         p->browse_time = 0;
-         cupsdRegisterPrinter(p);
-       }
-      }
-      else
-        cupsdLogMessage(CUPSD_LOG_DEBUG,
-                       "Computer name changed; ignored while sleeping");
-    }
+    notify_cancel(PSToken);
+    PSToken = 0;
   }
 }
 
@@ -400,7 +429,7 @@ sysEventThreadEntry(void)
   SCDynamicStoreRef    store    = NULL;/* System Config dynamic store */
   CFRunLoopSourceRef   powerRLS = NULL,/* Power runloop source */
                        storeRLS = NULL;/* System Config runloop source */
-  CFStringRef          key[5],         /* System Config keys */
+  CFStringRef          key[6],         /* System Config keys */
                        pattern[2];     /* System Config patterns */
   CFArrayRef           keys = NULL,    /* System Config key array*/
                        patterns = NULL;/* System Config pattern array */
@@ -436,43 +465,47 @@ sysEventThreadEntry(void)
   bzero(&storeContext, sizeof(storeContext));
   storeContext.info = &threadData;
 
-  store = SCDynamicStoreCreate(NULL, CFSTR("cupsd"),
+  store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"),
                                sysEventConfigurationNotifier, &storeContext);
 
   if (!ComputerNameKey)
-    ComputerNameKey = SCDynamicStoreKeyCreateComputerName(NULL);
+    ComputerNameKey = SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault);
+
+  if (!BTMMKey)
+    BTMMKey = SCDynamicStoreKeyCreate(kCFAllocatorDefault,
+                                      CFSTR("Setup:/Network/BackToMyMac"));
 
   if (!NetworkGlobalKeyIPv4)
     NetworkGlobalKeyIPv4 =
-        SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
+        SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
                                                    kSCDynamicStoreDomainState,
                                                   kSCEntNetIPv4);
 
   if (!NetworkGlobalKeyIPv6)
     NetworkGlobalKeyIPv6 =
-        SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
+        SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
                                                    kSCDynamicStoreDomainState,
                                                   kSCEntNetIPv6);
 
   if (!NetworkGlobalKeyDNS)
-    NetworkGlobalKeyDNS = 
-       SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 
+    NetworkGlobalKeyDNS =
+       SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
                                                   kSCDynamicStoreDomainState,
                                                   kSCEntNetDNS);
 
   if (!HostNamesKey)
-    HostNamesKey = SCDynamicStoreKeyCreateHostNames(NULL);
+    HostNamesKey = SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault);
 
   if (!NetworkInterfaceKeyIPv4)
     NetworkInterfaceKeyIPv4 =
-        SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+        SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
                                                      kSCDynamicStoreDomainState,
                                                      kSCCompAnyRegex,
                                                      kSCEntNetIPv4);
 
   if (!NetworkInterfaceKeyIPv6)
     NetworkInterfaceKeyIPv6 =
-        SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+        SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
                                                      kSCDynamicStoreDomainState,
                                                      kSCCompAnyRegex,
                                                      kSCEntNetIPv6);
@@ -482,27 +515,28 @@ sysEventThreadEntry(void)
       NetworkInterfaceKeyIPv4 && NetworkInterfaceKeyIPv6)
   {
     key[0]     = ComputerNameKey;
-    key[1]     = NetworkGlobalKeyIPv4;
-    key[2]     = NetworkGlobalKeyIPv6;
-    key[3]     = NetworkGlobalKeyDNS;
-    key[4]     = HostNamesKey;
+    key[1]     = BTMMKey;
+    key[2]     = NetworkGlobalKeyIPv4;
+    key[3]     = NetworkGlobalKeyIPv6;
+    key[4]     = NetworkGlobalKeyDNS;
+    key[5]     = HostNamesKey;
 
     pattern[0] = NetworkInterfaceKeyIPv4;
     pattern[1] = NetworkInterfaceKeyIPv6;
 
-    keys     = CFArrayCreate(NULL, (const void **)key,
-                                    sizeof(key) / sizeof(key[0]),
-                                   &kCFTypeArrayCallBacks);
+    keys     = CFArrayCreate(kCFAllocatorDefault, (const void **)key,
+                            sizeof(key) / sizeof(key[0]),
+                            &kCFTypeArrayCallBacks);
 
-    patterns = CFArrayCreate(NULL, (const void **)pattern,
+    patterns = CFArrayCreate(kCFAllocatorDefault, (const void **)pattern,
                              sizeof(pattern) / sizeof(pattern[0]),
                             &kCFTypeArrayCallBacks);
 
     if (keys && patterns &&
         SCDynamicStoreSetNotificationKeys(store, keys, patterns))
     {
-      if ((storeRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0))
-              != NULL)
+      if ((storeRLS = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault,
+                                                        store, 0)) != NULL)
       {
        CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS,
                           kCFRunLoopDefaultMode);
@@ -536,8 +570,8 @@ sysEventThreadEntry(void)
   timerContext.info = &threadData;
 
   threadData.timerRef =
-      CFRunLoopTimerCreate(NULL,
-                           CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L), 
+      CFRunLoopTimerCreate(kCFAllocatorDefault,
+                           CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
                           86400L * 365L * 10L, 0, 0, sysEventTimerNotifier,
                           &timerContext);
   CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData.timerRef,
@@ -617,19 +651,20 @@ sysEventPowerNotifier(
 
   switch (messageType)
   {
-    case kIOMessageCanSystemPowerOff:
-    case kIOMessageCanSystemSleep:
+    case kIOMessageCanSystemPowerOff :
+    case kIOMessageCanSystemSleep :
        threadData->sysevent.event |= SYSEVENT_CANSLEEP;
        break;
 
-    case kIOMessageSystemWillRestart:
-    case kIOMessageSystemWillPowerOff:
-    case kIOMessageSystemWillSleep:
+    case kIOMessageSystemWillRestart :
+    case kIOMessageSystemWillPowerOff :
+    case kIOMessageSystemWillSleep :
        threadData->sysevent.event |= SYSEVENT_WILLSLEEP;
+       threadData->sysevent.event &= ~SYSEVENT_WOKE;
        break;
 
-    case kIOMessageSystemHasPoweredOn:
-       /* 
+    case kIOMessageSystemHasPoweredOn :
+       /*
        * Because powered on is followed by a net-changed event, delay
        * before sending it.
        */
@@ -638,16 +673,62 @@ sysEventPowerNotifier(
        threadData->sysevent.event |= SYSEVENT_WOKE;
        break;
 
-    case kIOMessageSystemWillNotPowerOff:
-    case kIOMessageSystemWillNotSleep:
-#ifdef kIOMessageSystemWillPowerOn
-    case kIOMessageSystemWillPowerOn:
-#endif /* kIOMessageSystemWillPowerOn */
+    case kIOMessageSystemWillNotPowerOff :
+    case kIOMessageSystemWillNotSleep :
+#  ifdef kIOMessageSystemWillPowerOn
+    case kIOMessageSystemWillPowerOn :
+#  endif /* kIOMessageSystemWillPowerOn */
     default:
        sendit = 0;
        break;
   }
 
+  switch (messageType)
+  {
+    case kIOMessageCanSystemPowerOff :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageCanSystemPowerOff message.");
+       break;
+    case kIOMessageCanSystemSleep :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageCannSystemSleep message.");
+       break;
+    case kIOMessageSystemWillRestart :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageSystemWillRestart message.");
+       break;
+    case kIOMessageSystemWillPowerOff :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageSystemWillPowerOff message.");
+       break;
+    case kIOMessageSystemWillSleep :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageSystemWillSleep message.");
+       break;
+    case kIOMessageSystemHasPoweredOn :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageSystemHasPoweredOn message.");
+       break;
+    case kIOMessageSystemWillNotPowerOff :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageSystemWillNotPowerOff message.");
+       break;
+    case kIOMessageSystemWillNotSleep :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageSystemWillNotSleep message.");
+       break;
+#  ifdef kIOMessageSystemWillPowerOn
+    case kIOMessageSystemWillPowerOn :
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                        "Got kIOMessageSystemWillPowerOn message.");
+       break;
+#  endif /* kIOMessageSystemWillPowerOn */
+    default:
+        cupsdLogMessage(CUPSD_LOG_DEBUG, "Got unknown power message %d.",
+                        (int)messageType);
+       break;
+  }
+
   if (sendit == 0)
     IOAllowPowerChange(threadData->sysevent.powerKernelPort,
                        (long)messageArgument);
@@ -657,7 +738,7 @@ sysEventPowerNotifier(
 
     if (sendit == 1)
     {
-     /* 
+     /*
       * Send the event to the main thread now.
       */
 
@@ -667,7 +748,7 @@ sysEventPowerNotifier(
     }
     else
     {
-     /* 
+     /*
       * Send the event to the main thread after 1 to 2 seconds.
       */
 
@@ -679,7 +760,7 @@ sysEventPowerNotifier(
 
 
 /*
- * 'sysEventConfigurationNotifier()' - Computer name changed notification
+ * 'sysEventConfigurationNotifier()' - Network configuration change notification
  *                                     callback.
  */
 
@@ -693,12 +774,13 @@ sysEventConfigurationNotifier(
 
 
   threadData = (cupsd_thread_data_t *)context;
-  
+
   (void)store;                         /* anti-compiler-warning-code */
 
   CFRange range = CFRangeMake(0, CFArrayGetCount(changedKeys));
 
-  if (CFArrayContainsValue(changedKeys, range, ComputerNameKey))
+  if (CFArrayContainsValue(changedKeys, range, ComputerNameKey) ||
+      CFArrayContainsValue(changedKeys, range, BTMMKey))
     threadData->sysevent.event |= SYSEVENT_NAMECHANGED;
   else
   {
@@ -712,12 +794,12 @@ sysEventConfigurationNotifier(
   }
 
  /*
-  * Because we registered for several different kinds of change notifications 
-  * this callback usually gets called several times in a row. We use a timer to 
+  * Because we registered for several different kinds of change notifications
+  * this callback usually gets called several times in a row. We use a timer to
   * de-bounce these so we only end up generating one event for the main thread.
   */
 
-  CFRunLoopTimerSetNextFireDate(threadData->timerRef, 
+  CFRunLoopTimerSetNextFireDate(threadData->timerRef,
                                CFAbsoluteTimeGetCurrent() + 5);
 }
 
@@ -734,6 +816,8 @@ sysEventTimerNotifier(
   cupsd_thread_data_t  *threadData;    /* Thread context data */
 
 
+  (void)timer;
+
   threadData = (cupsd_thread_data_t *)context;
 
  /*
@@ -747,9 +831,239 @@ sysEventTimerNotifier(
     threadData->sysevent.event = 0;
   }
 }
-#endif /* __APPLE__ */
 
 
 /*
- * End of "$Id: sysman.c 6291 2007-02-19 21:54:27Z mike $".
+ * 'sysUpdate()' - Update the current system state.
  */
+
+static void
+sysUpdate(void)
+{
+  int                  i;              /* Looping var */
+  cupsd_sysevent_t     sysevent;       /* The system event */
+  cupsd_printer_t      *p;             /* Printer information */
+
+
+ /*
+  * Drain the event pipe...
+  */
+
+  while (read((int)SysEventPipes[0], &sysevent, sizeof(sysevent))
+             == sizeof(sysevent))
+  {
+    if (sysevent.event & SYSEVENT_CANSLEEP)
+    {
+     /*
+      * If there are active printers that don't have the connecting-to-device
+      * or cups-waiting-for-job-completed printer-state-reason then cancel the
+      * sleep request, i.e., these reasons indicate a job that is not actively
+      * doing anything...
+      */
+
+      for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+           p;
+          p = (cupsd_printer_t *)cupsArrayNext(Printers))
+      {
+        if (p->job)
+        {
+         for (i = 0; i < p->num_reasons; i ++)
+           if (!strcmp(p->reasons[i], "connecting-to-device") ||
+               !strcmp(p->reasons[i], "cups-waiting-for-job-completed"))
+             break;
+
+         if (!p->num_reasons || i >= p->num_reasons)
+           break;
+        }
+      }
+
+      if (p)
+      {
+        cupsdLogMessage(CUPSD_LOG_INFO,
+                       "System sleep canceled because printer %s is active.",
+                       p->name);
+        IOCancelPowerChange(sysevent.powerKernelPort,
+                           sysevent.powerNotificationID);
+      }
+      else
+      {
+       cupsdLogMessage(CUPSD_LOG_DEBUG, "System wants to sleep.");
+        IOAllowPowerChange(sysevent.powerKernelPort,
+                          sysevent.powerNotificationID);
+      }
+    }
+
+    if (sysevent.event & SYSEVENT_WILLSLEEP)
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG, "System going to sleep.");
+
+      Sleeping = 1;
+
+      cupsdCleanDirty();
+
+     /*
+      * If we have no printing jobs, allow the power change immediately.
+      * Otherwise set the SleepJobs time to 10 seconds in the future when
+      * we'll take more drastic measures...
+      */
+
+      if (cupsArrayCount(PrintingJobs) == 0)
+      {
+       cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
+       IOAllowPowerChange(sysevent.powerKernelPort,
+                          sysevent.powerNotificationID);
+      }
+      else
+      {
+       /*
+       * If there are active printers that don't have the connecting-to-device
+       * or cups-waiting-for-job-completed printer-state-reasons then delay the
+       * sleep request, i.e., these reasons indicate a job is active...
+       */
+
+       for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+            p;
+            p = (cupsd_printer_t *)cupsArrayNext(Printers))
+       {
+         if (p->job)
+         {
+           for (i = 0; i < p->num_reasons; i ++)
+             if (!strcmp(p->reasons[i], "connecting-to-device") ||
+                 !strcmp(p->reasons[i], "cups-waiting-for-job-completed"))
+               break;
+
+           if (!p->num_reasons || i >= p->num_reasons)
+             break;
+         }
+       }
+
+       if (p)
+       {
+         cupsdLogMessage(CUPSD_LOG_INFO,
+                         "System sleep delayed because printer %s is active.",
+                         p->name);
+
+         LastSysEvent = sysevent;
+         SleepJobs    = time(NULL) + 10;
+       }
+       else
+       {
+         cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
+         IOAllowPowerChange(sysevent.powerKernelPort,
+                            sysevent.powerNotificationID);
+       }
+      }
+    }
+
+    if (sysevent.event & SYSEVENT_WOKE)
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG, "System woke from sleep.");
+      IOAllowPowerChange(sysevent.powerKernelPort,
+                         sysevent.powerNotificationID);
+      Sleeping = 0;
+
+     /*
+      * Make sure jobs that were queued prior to the system going to sleep don't
+      * get canceled right away...
+      */
+
+      if (MaxJobTime > 0)
+      {
+        cupsd_job_t    *job;           /* Current job */
+
+        for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+             job;
+             job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+        {
+          if (job->cancel_time)
+          {
+            ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
+                                                             "job-cancel-after",
+                                                             IPP_TAG_INTEGER);
+
+            if (cancel_after)
+              job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
+            else
+              job->cancel_time = time(NULL) + MaxJobTime;
+          }
+        }
+      }
+
+      if (NameChanged)
+        sysUpdateNames();
+
+      cupsdCheckJobs();
+    }
+
+    if (sysevent.event & SYSEVENT_NETCHANGED)
+    {
+      if (Sleeping)
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                       "System network configuration changed - "
+                       "ignored while sleeping.");
+      else
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                       "System network configuration changed.");
+    }
+
+    if (sysevent.event & SYSEVENT_NAMECHANGED)
+    {
+      if (Sleeping)
+      {
+        NameChanged = 1;
+
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                       "Computer name or BTMM domains changed - ignored while "
+                       "sleeping.");
+      }
+      else
+      {
+        cupsdLogMessage(CUPSD_LOG_DEBUG,
+                       "Computer name or BTMM domains changed.");
+
+        sysUpdateNames();
+      }
+    }
+  }
+}
+
+
+/*
+ * 'sysUpdateNames()' - Update computer and/or BTMM domains.
+ */
+
+static void
+sysUpdateNames(void)
+{
+  cupsd_printer_t      *p;             /* Current printer */
+
+
+  NameChanged = 0;
+
+ /*
+  * De-register the individual printers...
+  */
+
+  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+       p;
+       p = (cupsd_printer_t *)cupsArrayNext(Printers))
+    cupsdDeregisterPrinter(p, 1);
+
+#  if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+ /*
+  * Update the computer name and BTMM domain list...
+  */
+
+  cupsdUpdateDNSSDName();
+#  endif /* HAVE_DNSSD || HAVE_AVAHI */
+
+ /*
+  * Now re-register them...
+  */
+
+  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+       p;
+       p = (cupsd_printer_t *)cupsArrayNext(Printers))
+    cupsdRegisterPrinter(p);
+}
+#endif /* __APPLE__ */