]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Added more debug stuff to lpd backend.
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 19 Apr 2000 21:26:00 +0000 (21:26 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 19 Apr 2000 21:26:00 +0000 (21:26 +0000)
Added LPD server daemon.

Makefile updates.

formtops filter updates.

Fixed background color for ESP web files.

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@1022 7a7537e8-13f0-0310-91df-b6672ffda945

backend/lpd.c
doc/cups.css
filter/form-tree.c
filter/form.h
pstoraster/Makefile
scheduler/Makefile
scheduler/cups-lpd.c [new file with mode: 0644]

index f34de677f7a3e571c2ebfdce6bcd7fe0eb96ff41..20de8d8b77246a56cfdf3968d795f475fc42f121 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: lpd.c,v 1.18 2000/03/21 04:03:23 mike Exp $"
+ * "$Id: lpd.c,v 1.19 2000/04/19 21:25:57 mike Exp $"
  *
  *   Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
  *
@@ -201,6 +201,8 @@ lpd_command(int  fd,                /* I - Socket connection to LPD host */
   * Send the command...
   */
 
+  fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
+
   if (send(fd, buf, bytes, 0) < bytes)
     return (-1);
 
@@ -208,6 +210,8 @@ lpd_command(int  fd,                /* I - Socket connection to LPD host */
   * Read back the status from the command and return it...
   */
 
+  fprintf(stderr, "DEBUG: Reading command status...\n");
+
   if (recv(fd, &status, 1, 0) < 1)
     return (-1);
 
@@ -300,6 +304,8 @@ lpd_queue(char *hostname,   /* I - Host to connect to */
       break;
   }
 
+  fprintf(stderr, "INFO: Connected on port %d...\n", port);
+
  /*
   * Next, open the print file and figure out its size...
   */
@@ -410,5 +416,5 @@ lpd_queue(char *hostname,   /* I - Host to connect to */
 
 
 /*
- * End of "$Id: lpd.c,v 1.18 2000/03/21 04:03:23 mike Exp $".
+ * End of "$Id: lpd.c,v 1.19 2000/04/19 21:25:57 mike Exp $".
  */
index a07ace0fc78ada17166a60be6533385362acdacc..9285a5b5eeccefce1f27d016062469ab258d3a2d 100644 (file)
@@ -1,3 +1,4 @@
-H1 { font-family: sans-serif; }
-H2 { font-family: sans-serif; }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
 TH { text-align: left }
+
index 0e7c2350e80c170dfd56f227265471de63c3d416..50463f2bb8fc8c165aa9e635eb620781bc6a7a69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: form-tree.c,v 1.2 2000/04/18 19:41:11 mike Exp $"
+ * "$Id: form-tree.c,v 1.3 2000/04/19 21:25:58 mike Exp $"
  *
  *   CUPS form document tree routines for the Common UNIX Printing
  *   System (CUPS).
 #include "form.h"
 
 
+/*
+ * Local functions...
+ */
+
+static int     compare_attr(attr_t *a0, attr_t *a1);
+static int     compare_elements(char **e0, char **e1);
+static int     parse_attr(tree_t *t, FILE *fp);
+static int     parse_element(tree_t *t, FILE *fp);
+
+
+/*
+ * Local globals...
+ */
+
+static char    *elements[] =
+               {
+                 "",
+                 "!--",
+                 "ARC",
+                 "BOX",
+                 "BR",
+                 "B",
+                 "CUPSFORM",
+                 "DEFVAR",
+                 "FONT",
+                 "H1",
+                 "H2",
+                 "H3",
+                 "H4",
+                 "H5",
+                 "H6",
+                 "HEAD",
+                 "IMG",
+                 "I",
+                 "LINE",
+                 "PAGE",
+                 "PIE",
+                 "POLY",
+                 "PRE",
+                 "P",
+                 "RECT",
+                 "TEXT",
+                 "TT",
+                 "VAR"
+               };
+
+
 /*
  * 'formDelete()' - Delete a node and its children.
  */
@@ -59,9 +106,51 @@ formGetAttr(tree_t     *t,          /* I - Tree node */
  */
 
 tree_t *                               /* O - New tree node */
-formNew(element_t e,                   /* I - Element type */
-        tree_t    *p)                  /* I - Parent node */
+formNew(tree_t    *p)                  /* I - Parent node */
 {
+  tree_t       *t;                     /* New tree node */
+
+
+ /*
+  * Allocate the new node...
+  */
+
+  if ((t = (tree_t *)calloc(sizeof(tree_t), 1)) == NULL)
+    return (NULL);
+
+ /*
+  * Set/copy attributes...
+  */
+
+  if (p == NULL)
+  {
+    t->bg[0]    = 1.0;
+    t->bg[1]    = 1.0;
+    t->bg[2]    = 1.0;
+    t->halign   = HALIGN_LEFT;
+    t->valign   = VALIGN_MIDDLE;
+    t->typeface = "Courier";
+    t->size     = 12.0;
+  }
+  else
+  {
+    memcpy(t, p, sizeof(tree_t));
+
+    t->prev       = NULL;
+    t->next       = NULL;
+    t->child      = NULL;
+    t->last_child = NULL;
+    t->parent     = NULL;
+    t->num_attrs  = 0;
+    t->attrs      = NULL;
+    t->data       = NULL;
+  }
+
+ /*
+  * Return the new node...
+  */
+
+  return (t);
 }
 
 
@@ -73,6 +162,255 @@ tree_t *                           /* O - New form tree */
 formRead(FILE   *fp,                   /* I - File to read from */
          tree_t *p)                    /* I - Parent node */
 {
+  int          ch,                     /* Character from file */
+               closech,                /* Closing character */
+               have_whitespace;        /* Leading whitespace? */
+  static char  s[10240];               /* String from file */
+  uchar                *ptr,                   /* Pointer in string */
+               glyph[16],              /* Glyph name (&#nnn;) */
+               *glyphptr;              /* Pointer in glyph string */
+  tree_t       *tree,                  /* "top" of this tree */
+               *t,                     /* New tree node */
+               *prev,                  /* Previous tree node */
+               *temp;                  /* Temporary looping var */
+  uchar                *face,                  /* Typeface for FONT tag */
+               *color,                 /* Color for FONT tag */
+               *size;                  /* Size for FONT tag */
+
+
+ /*
+  * Start off with no previous tree node...
+  */
+
+  prev = NULL;
+  tree = NULL;
+
+ /*
+  * Parse data until we hit end-of-file...
+  */
+
+  while ((ch = getc(fp)) != EOF)
+  {
+   /*
+    * Ignore leading whitespace...
+    */
+
+    have_whitespace = 0;
+    closech         = '/';
+
+    if (p == NULL || !p->preformatted)
+    {
+      while (isspace(ch))
+      {
+        have_whitespace = 1;
+        ch              = getc(fp);
+      }
+
+      if (ch == EOF)
+        break;
+    }
+
+   /*
+    * Allocate a new tree node - use calloc() to get zeroed data...
+    */
+
+    t = formNew(p);
+
+   /*
+    * See what the character was...
+    */
+
+    if (ch == '<')
+    {
+     /*
+      * Markup char; grab the next char to see if this is a /...
+      */
+
+      ch = getc(fp);
+      if (ch == ' ')
+      {
+       /*
+        * Illegal lone "<"!  Ignore it...
+       */
+
+       free(t);
+       continue;
+      }
+      
+      if (ch != '/')
+        ungetc(ch, fp);
+
+      if (parse_element(t, fp) < 0)
+      {
+        free(t);
+        break;
+      }
+
+      if ((closech = getc(fp)) == '/')
+        getc(fp);
+
+     /*
+      * If this is the matching close mark, or if we are starting the same
+      * element, or if we've completed a list, we're done!
+      */
+
+      if (ch == '/')
+      {
+       /*
+        * Close element; find matching element...
+        */
+
+        for (temp = p; temp != NULL; temp = temp->p)
+          if (temp->element == t->element)
+            break;
+
+        free(t);
+
+       if (temp != NULL)
+          break;
+       else
+         continue;
+      }
+    }
+    else if (t->preformatted)
+    {
+     /*
+      * Read a pre-formatted string into the current tree node...
+      */
+
+      ptr = s;
+      while (ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
+      {
+        if (ch == '&')
+        {
+          for (glyphptr = glyph;
+               (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
+               glyphptr ++)
+            if (!isalnum(ch))
+              break;
+            else
+              *glyphptr = ch;
+
+          *glyphptr = '\0';
+         if (atoi(glyph) > 0)
+           ch = atoi(glyph);
+         else if (strcmp(glyph, "lt") == 0)
+           ch = '<';
+         else if (strcmp(glyph, "gt") == 0)
+           ch = '>';
+         else if (strcmp(glyph, "quot") == 0)
+           ch = '\'';
+         else if (strcmp(glyph, "nbsp") == 0)
+           ch = ' ';
+         else
+           ch = '&';
+        }
+
+        if (ch != 0)
+          *ptr++ = ch;
+
+        if (ch == '\n')
+          break;
+
+        ch = getc(fp);
+      }
+
+      *ptr = '\0';
+
+      if (ch == '<')
+        ungetc(ch, fp);
+
+      t->element = ELEMENT_FRAGMENT;
+      t->data    = strdup(s);
+    }
+    else
+    {
+     /*
+      * Read the next string fragment...
+      */
+
+      ptr = s;
+      if (have_whitespace)
+        *ptr++ = ' ';
+
+      while (!isspace(ch) && ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
+      {
+        if (ch == '&')
+        {
+          for (glyphptr = glyph;
+               (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
+               glyphptr ++)
+            if (!isalnum(ch))
+              break;
+            else
+              *glyphptr = ch;
+
+          *glyphptr = '\0';
+         if (atoi(glyph) > 0)
+           ch = atoi(glyph);
+         else if (strcmp(glyph, "lt") == 0)
+           ch = '<';
+         else if (strcmp(glyph, "gt") == 0)
+           ch = '>';
+         else if (strcmp(glyph, "quot") == 0)
+           ch = '\'';
+         else if (strcmp(glyph, "nbsp") == 0)
+           ch = ' ';
+         else
+           ch = '&';
+        }
+
+        if (ch != 0)
+          *ptr++ = ch;
+
+        ch = getc(fp);
+      }
+
+      if (isspace(ch))
+        *ptr++ = ' ';
+
+      *ptr = '\0';
+
+      if (ch == '<')
+        ungetc(ch, fp);
+
+      t->element = ELEMENT_FRAGMENT;
+      t->data    = strdup(s);
+    }
+
+   /*
+    * If the p tree pointer is not NULL and this is the first
+    * entry we've read, set the child pointer...
+    */
+
+    if (p != NULL && prev == NULL)
+      p->child = t;
+
+    if (p != NULL)
+      p->last_child = t;
+
+   /*
+    * Do the prev/next links...
+    */
+
+    t->parent = p;
+    t->prev   = prev;
+    if (prev != NULL)
+      prev->next = t;
+    else
+      tree = t;
+
+    prev = t;
+
+   /*
+    * Do child stuff as needed...
+    */
+
+    if (closech == '>')
+      t->child = formRead(t, fp);
+  }  
+
+  return (tree);
 }
 
 
@@ -89,5 +427,196 @@ formSetAttr(tree_t     *t,         /* I - Tree node */
 
 
 /*
- * End of "$Id: form-tree.c,v 1.2 2000/04/18 19:41:11 mike Exp $".
+ * 'compare_attr()' - Compare two attributes.
+ */
+
+static int                             /* O - -1 if a0 < a1, etc. */
+compare_attr(attr_t *a0,               /* I - First attribute */
+             attr_t *a1)               /* I - Second attribute */
+{
+  return (strcasecmp(a0->name, a1->name));
+}
+
+
+/*
+ * 'compare_elements()' - Compare two elements.
+ */
+
+static int                             /* O - -1 if e0 < e1, etc. */
+compare_elements(char **e0,            /* I - First element */
+                 char **e1)            /* I - Second element */
+{
+  return (strcasecmp(*e0, *e1));
+}
+
+
+/*
+ * 'parse_attr()' - Parse an element attribute string.
+ */
+
+static int                             /* O - -1 on error, 0 on success */
+parse_attr(tree_t *t,                  /* I - Current tree node */
+           FILE   *fp)                 /* I - Input file */
+{
+  char name[1024],                     /* Name of attr */
+       value[10240],                   /* Value of attr */
+       *ptr;                           /* Temporary pointer */
+  int  ch;                             /* Character from file */
+
+
+  ptr = name;
+  while ((ch = getc(fp)) != EOF)
+    if (isalnum(ch))
+    {
+      if (ptr < (name + sizeof(name) - 1))
+        *ptr++ = ch;
+    }
+    else
+      break;
+
+  *ptr = '\0';
+
+  while (isspace(ch) || ch == '\r')
+    ch = getc(fp);
+
+  switch (ch)
+  {
+    default :
+        ungetc(ch, fp);
+        return (formSetAttr(t, name, NULL));
+    case EOF :
+        return (-1);
+    case '=' :
+        ptr = value;
+        ch  = getc(fp);
+
+        while (isspace(ch) || ch == '\r')
+          ch = getc(fp);
+
+        if (ch == EOF)
+          return (-1);
+
+        if (ch == '\'')
+        {
+          while ((ch = getc(fp)) != EOF)
+            if (ch == '\'')
+              break;
+            else if (ptr < (value + sizeof(value) - 1))
+              *ptr++ = ch;
+
+          *ptr = '\0';
+        }
+        else if (ch == '\"')
+        {
+          while ((ch = getc(fp)) != EOF)
+            if (ch == '\"')
+              break;
+            else if (ptr < (value + sizeof(value) - 1))
+              *ptr++ = ch;
+
+          *ptr = '\0';
+        }
+        else
+        {
+          *ptr++ = ch;
+          while ((ch = getc(fp)) != EOF)
+            if (isspace(ch) || ch == '>' || ch == '/' || ch == '\r')
+              break;
+            else if (ptr < (value + sizeof(value) - 1))
+              *ptr++ = ch;
+
+          *ptr = '\0';
+          if (ch == '>' || ch == '/')
+            ungetc(ch, fp);
+        }
+
+        return (formSetAttr(t, name, value));
+  }
+}
+
+
+/*
+ * 'parse_element()' - Parse an element.
+ */
+
+static int                             /* O - -1 on error or ELEMENT_nnnn */
+parse_element(tree_t *t,               /* I - Current tree node */
+              FILE   *fp)              /* I - Input file */
+{
+  int  ch;                             /* Character from file */
+  char element[255],                   /* Element string... */
+       *eptr,                          /* Current character... */
+       comment[10240],                 /* Comment string */
+       *cptr,                          /* Current char... */
+       **temp;                         /* Element variable entry */
+
+
+  eptr = element;
+
+  while ((ch = getc(fp)) != EOF && eptr < (element + sizeof(element) - 1))
+    if (ch == '>' || ch == '/' || isspace(ch))
+      break;
+    else
+      *eptr++ = ch;
+
+  *eptr = '\0';
+
+  if (ch == EOF)
+    return (ELEMENT_ERROR);
+
+  eptr = element;
+  temp = bsearch(&mptr, elements, sizeof(elements) / sizeof(elements[0]),
+                 sizeof(elements[0]),
+                 (int (*)(const void *, const void *))compare_elements);
+
+  if (temp == NULL)
+  {
+   /*
+    * Unrecognized element stuff...
+    */
+
+    t->element = ELEMENT_COMMENT;
+    strcpy(comment, element);
+    cptr = comment + strlen(comment);
+  }
+  else
+  {
+    t->element = (element_t)((char **)temp - elements);
+    cptr       = comment;
+  }
+
+  if (t->element == ELEMENT_COMMENT)
+  {
+    while (ch != EOF && ch != '>' && cptr < (comment + sizeof(comment) - 1))
+    {
+      *cptr++ = ch;
+      ch = getc(fp);
+    }
+
+    *cptr   = '\0';
+    t->data = strdup(comment);
+  }
+  else
+  {
+    while (ch != EOF && ch != '>' && ch != '/')
+    {
+      if (!isspace(ch))
+      {
+        ungetc(ch, fp);
+        parse_variable(t, fp);
+      }
+
+      ch = getc(fp);
+    }
+
+    if (ch != EOF)
+      ungetc(ch, fp);
+  }
+
+  return (t->element);
+}
+
+
+/*
+ * End of "$Id: form-tree.c,v 1.3 2000/04/19 21:25:58 mike Exp $".
  */
index afefb7eac0036f60d072d1c8872c477b020a7ea1..808d168329d7e3f28f9985d5737d9e0e700a163a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: form.h,v 1.2 2000/04/18 19:41:11 mike Exp $"
+ * "$Id: form.h,v 1.3 2000/04/19 21:25:59 mike Exp $"
  *
  *   CUPS form header file for the Common UNIX Printing System (CUPS).
  *
@@ -35,8 +35,9 @@
 
 typedef enum
 {
-  ELEMENT_COMMENT = -2,        /* <!-- .... --> */
-  ELEMENT_FILE,                /* Pseudo element, not in file, but above */
+  ELEMENT_FILE = -1,           /* Pseudo element, not in file, but above */
+  ELEMENT_FRAGMENT,    /* Text fragment */
+  ELEMENT_COMMENT,     /* <!-- .... --> */
   ELEMENT_ARC,
   ELEMENT_BOX,
   ELEMENT_BR,
@@ -135,6 +136,7 @@ typedef struct tree_str
   float                        x, y, w, h;     /* Position and size in points */
   float                        bg[3], fg[3];   /* Colors of element */
   float                        thickness;      /* Thickness of lines */
+  int                  preformatted;   /* Preformatted text? */
   float                        size;           /* Height of text in points */
   char                 *typeface;      /* Typeface of text */
   style_t              style;          /* Style of text */
@@ -162,12 +164,12 @@ extern ppd_file_t *PPD;           /* PPD file */
 
 extern void    formDelete(tree_t *t);
 extern char    *formGetAttr(tree_t *t, const char *name);
-extern tree_t  *formNew(element_t e, tree_t *p);
+extern tree_t  *formNew(tree_t *p);
 extern tree_t  *formRead(FILE *fp, tree_t *p);
 extern void    formSetAttr(tree_t *t, const char *name, const char *value);
 extern void    formWrite(tree_t *p);
 
 
 /*
- * End of "$Id: form.h,v 1.2 2000/04/18 19:41:11 mike Exp $".
+ * End of "$Id: form.h,v 1.3 2000/04/19 21:25:59 mike Exp $".
  */
index 14393284dbd667b4536033689a1188a59ed36216..5a921c97ec088fb70c23410626a3a71d2c2e94eb 100644 (file)
@@ -1,5 +1,5 @@
 #
-# "$Id: Makefile,v 1.20 2000/03/30 05:19:27 mike Exp $"
+# "$Id: Makefile,v 1.21 2000/04/19 21:25:59 mike Exp $"
 #
 #   GNU Ghostscript makefile for the Common UNIX Printing System (CUPS).
 #
@@ -336,7 +336,7 @@ LIBOBJS     =       gconfig.o \
                zupath.o \
                zusparam.o \
                zvmem2.o \
-               zvmem.o \
+               zvmem.o
 
 OBJS   =       $(LIBOBJS) genarch.o pstoraster.o
 
@@ -431,5 +431,5 @@ pstoraster: pstoraster.o libgs.a ../Makedefs ../cups/$(LIBCUPS)
 pstoraster.o:  arch.h ../config.h ../Makedefs
 
 #
-# End of "$Id: Makefile,v 1.20 2000/03/30 05:19:27 mike Exp $".
+# End of "$Id: Makefile,v 1.21 2000/04/19 21:25:59 mike Exp $".
 #
index eff621cd7cc67be50556552a18a987a0ec911c64..83b514887eabc86e8064a5098a47055a409a9f05 100644 (file)
@@ -1,5 +1,5 @@
 #
-# "$Id: Makefile,v 1.25 2000/03/30 05:19:28 mike Exp $"
+# "$Id: Makefile,v 1.26 2000/04/19 21:26:00 mike Exp $"
 #
 #   Scheduler Makefile for the Common UNIX Printing System (CUPS).
 #
@@ -27,14 +27,15 @@ include ../Makedefs
 CUPSDOBJS =    auth.o banners.o cert.o classes.o client.o conf.o devices.o \
                dirsvc.o main.o ipp.o listen.o job.o log.o ppds.o printers.o
 MIMEOBJS =     filter.o mime.o type.o
-OBJS   =       $(CUPSDOBJS) $(MIMEOBJS) cups-polld.o testmime.o testspeed.o
+OBJS   =       $(CUPSDOBJS) $(MIMEOBJS) cups-lpd.o cups-polld.o testmime.o \
+               testspeed.o
 
 
 #
 # Make everything...
 #
 
-all:   cupsd cups-polld libmime.a testmime testspeed
+all:   cupsd cups-lpd cups-polld libmime.a testmime testspeed
 
 
 #
@@ -42,7 +43,7 @@ all:  cupsd cups-polld libmime.a testmime testspeed
 #
 
 clean:
-       $(RM) $(OBJS) cupsd cups-polld libmime.a testmime testspeed
+       $(RM) $(OBJS) cupsd cups-lpd cups-polld libmime.a testmime testspeed
 
 
 #
@@ -54,6 +55,7 @@ install:
        $(INSTALL_BIN) cupsd $(SBINDIR)
        $(CHMOD) g-rwx,o-rwx $(SBINDIR)/cupsd
        -$(MKDIR) $(SERVERBIN)/daemon
+       $(INSTALL_BIN) cups-lpd $(SERVERBIN)/daemon
        $(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon
        -$(MKDIR) $(SERVERROOT)/certs
        -$(MKDIR) $(SERVERROOT)/interfaces
@@ -76,6 +78,18 @@ $(CUPSDOBJS):        auth.h banners.h cert.h classes.h client.h conf.h \
                ../cups/language.h ../cups/string.h
 
 
+#
+# Make the line printer daemon, "cups-lpd".
+#
+
+cups-lpd:      cups-lpd.o ../cups/$(LIBCUPS)
+       echo Linking $@...
+       $(CC) $(LDFLAGS) -o cups-lpd cups-lpd.o $(LIBS)
+
+cups-lpd.o:    ../cups/cups.h ../cups/http.h ../cups/ipp.h \
+               ../cups/language.h ../cups/string.h
+
+
 #
 # Make the polling daemon, "cups-polld".
 #
@@ -125,5 +139,5 @@ $(OBJS):    ../config.h ../Makedefs
 
 
 #
-# End of "$Id: Makefile,v 1.25 2000/03/30 05:19:28 mike Exp $".
+# End of "$Id: Makefile,v 1.26 2000/04/19 21:26:00 mike Exp $".
 #
diff --git a/scheduler/cups-lpd.c b/scheduler/cups-lpd.c
new file mode 100644 (file)
index 0000000..6859259
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ * "$Id: cups-lpd.c,v 1.1 2000/04/19 21:26:00 mike Exp $"
+ *
+ *   Line Printer Daemon interface for the Common UNIX Printing System (CUPS).
+ *
+ *   Copyright 1997-2000 by Easy Software Products, all rights reserved.
+ *
+ *   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-3111 USA
+ *
+ *       Voice: (301) 373-9603
+ *       EMail: cups-info@cups.org
+ *         WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <cups/language.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+
+/*
+ * LPD "mini-daemon" for CUPS.  This program must be used in conjunction
+ * with inetd or another similar program that monitors ports and starts
+ * daemons for each client connection.  A typical configuration is:
+ *
+ *    printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
+ *
+ * This daemon implements most of RFC 1179 (the unofficial LPD specification)
+ * except for:
+ *
+ *     - This daemon does not check to make sure that the source port is
+ *       between 721 and 731, since it isn't necessary for proper
+ *       functioning, and port-based security is no security at all!
+ *
+ *     - The "Print any waiting jobs" command is a no-op.
+ *
+ * The LPD-to-IPP mapping is as defined in RFC 2569.
+ */
+
+/*
+ * Prototypes...
+ */
+
+int    recv_print_job(const char *dest);
+int    send_short_state(const char *dest, const char *list);
+int    send_long_state(const char *dest, const char *list);
+int    remove_jobs(const char *dest, const char *agent, const char *list);
+
+
+/*
+ * 'main()' - Process an incoming LPD request...
+ */
+
+int                    /* O - Exit status */
+main(int  argc,                /* I - Number of command-line arguments */
+     char *argv[])     /* I - Command-line arguments */
+{
+  char line[1024],     /* Command string */
+       command,        /* Command code */
+       *dest,          /* Pointer to destination */
+       *list,          /* Pointer to list */
+       *agent,         /* Pointer to user */
+       status;         /* Status for client */
+
+
+ /*
+  * Don't buffer the output...
+  */
+
+  setbuf(stdout, NULL);
+
+ /*
+  * RFC1179 specifies that only 1 daemon command can be received for
+  * every connection.
+  */
+
+  if (fgets(line, sizeof(line), stdin) == NULL)
+  {
+   /*
+    * Unable to get command from client!  Send an error status and return.
+    */
+
+    putchar(1);
+    return (1);
+  }
+
+ /*
+  * The first byte is the command byte.  After that will be the queue name,
+  * resource list, and/or user name.
+  */
+
+  command = line[0];
+  dest    = line + 1;
+
+  for (list = dest + 1; *list && !isspace(*list); list ++);
+
+  while (isspace(*list))
+    *list++ = '\0';
+
+ /*
+  * Do the command...
+  */
+
+  switch (command)
+  {
+    default : /* Unknown command */
+       putchar(1);
+
+        status = 1;
+       break;
+
+    case 0x01 : /* Print any waiting jobs */
+       putchar(0);
+
+        status = 0;
+       break;
+
+    case 0x02 : /* Receive a printer job */
+       putchar(0);
+
+        status = recv_print_job(dest);
+       break;
+
+    case 0x03 : /* Send queue state (short) */
+       putchar(0);
+
+        status = send_short_state(dest, list);
+       break;
+
+    case 0x04 : /* Send queue state (long) */
+       putchar(0);
+
+        status = send_long_state(dest, list);
+       break;
+
+    case 0x05 : /* Remove jobs */
+       putchar(0);
+
+       /*
+        * Grab the agent and skip to the list of users and/or jobs.
+       */
+
+        agent = list;
+
+       for (; *list && !isspace(*list); list ++);
+       while (isspace(*list))
+         *list++ = '\0';
+
+        status = remove_jobs(dest, agent, list);
+       break;
+  }
+
+  return (status);
+}
+
+
+/*
+ * 'recv_print_job()' - Receive a print job from the client.
+ */
+
+int                                    /* O - Command status */
+recv_print_job(const char *dest)       /* I - Destination */
+{
+  int          i;                      /* Looping var */
+  int          status;                 /* Command status */
+  FILE         *fp;                    /* Temporary file */
+  char         filename[1024];         /* Filename */
+  int          bytes;                  /* Bytes received */
+  char         line[1024],             /* Line from file/stdin */
+               command,                /* Command from line */
+               *count,                 /* Number of bytes */
+               *name;                  /* Name of file */
+  int          num_data;               /* Number of data files */
+  char         data[32][256];          /* Data files */
+  const char   *tmpdir;                /* Temporary directory */
+  char         user[1024],             /* User name */
+               title[1024],            /* Job title */
+               docname[1024];          /* Document name */
+  http_t       *http;                  /* HTTP server connection */
+  cups_lang_t  *language;              /* Language information */
+  ipp_t                *request,               /* IPP request */
+               *response;              /* IPP response */
+  char         uri[HTTP_MAX_URI];      /* Printer URI */
+
+
+  status   = 0;
+  num_data = 0;
+  if ((tmpdir = getenv("TMP")) == NULL)
+    tmpdir = "/var/tmp";
+
+  while (fgets(line, sizeof(line), stdin) != NULL)
+  {
+    if (strlen(line) < 2)
+    {
+      status = 1;
+      break;
+    }
+
+    command = line[0];
+    count   = line + 1;
+
+    for (name = count + 1; *name && !isspace(*name); name ++);
+    while (isspace(*name))
+      *name++ = '\0';
+
+    switch (command)
+    {
+      default :
+      case 0x01 : /* Abort */
+          status = 1;
+         break;
+      case 0x02 : /* Receive control file */
+          if (strlen(name) < 2)
+         {
+           putchar(1);
+           status = 1;
+           break;
+         }
+
+          snprintf(filename, sizeof(filename), "%s/%06d-0", tmpdir, getpid());
+         break;
+      case 0x03 : /* Receive data file */
+          if (strlen(name) < 2)
+         {
+           putchar(1);
+           status = 1;
+           break;
+         }
+
+          name[strlen(name) - 1] = '\0'; /* Strip LF */
+         strncpy(data[num_data], name, sizeof(data[0]) - 1);
+         data[num_data][sizeof(data[0]) - 1] = '\0';
+
+          num_data ++;
+          snprintf(filename, sizeof(filename), "%s/%06d-%d", tmpdir, getpid(),
+                  num_data);
+         break;
+    }
+
+    putchar(status);
+
+    if (status)
+      break;
+
+   /*
+    * Try opening the temp file...
+    */
+
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+      putchar(1);
+      status = 1;
+      break;
+    }
+
+   /*
+    * Copy the data or control file from the client...
+    */
+
+    for (i = atoi(count); i > 0; i -= bytes)
+    {
+      if (i > sizeof(line))
+        bytes = sizeof(line);
+      else
+        bytes = i;
+
+      if ((bytes = fread(line, 1, bytes, stdin)) > 0)
+        bytes = fwrite(line, 1, bytes, fp);
+
+      if (bytes < 1)
+      {
+        status = 1;
+       break;
+      }
+    }
+
+   /*
+    * Read trailing nul...
+    */
+
+    if (!status)
+    {
+      fread(line, 1, 1, stdin);
+      status = line[0];
+    }
+
+   /*
+    * Close the file and send an acknowledgement...
+    */
+
+    fclose(fp);
+
+    putchar(status);
+
+    if (status)
+      break;
+  }
+
+  if (!status)
+  {
+   /*
+    * Process the control file and print stuff...
+    */
+
+    snprintf(filename, sizeof(filename), "%s/%06d-0", tmpdir, getpid());
+    if ((fp = fopen(filename, "rb")) == NULL)
+      status = 1;
+    else if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+      status = 1;
+    else
+    {
+      language    = cupsLangDefault();
+      title[0]    = '\0';
+      user[0]     = '\0';
+      docname[0]  = '\0';
+
+      while (fgets(line, sizeof(line), fp) != NULL)
+      {
+       /*
+        * Strip the trailing newline...
+       */
+
+        if (line[0])
+         line[strlen(line) - 1] = '\0';
+
+       /*
+        * Process control lines...
+       */
+
+       switch (line[0])
+       {
+         case 'J' : /* Job name */
+             strcpy(title, line + 1);
+             break;
+         case 'N' : /* Document name */
+             strcpy(docname, line + 1);
+             break;
+         case 'P' : /* User identification */
+             strcpy(user, line + 1);
+             break;
+         case 'c' : /* Plot CIF file */
+         case 'd' : /* Print DVI file */
+         case 'f' : /* Print formatted file */
+         case 'g' : /* Plot file */
+         case 'l' : /* Print file leaving control characters (raw) */
+         case 'n' : /* Print ditroff output file */
+         case 'o' : /* Print PostScript output file */
+         case 'p' : /* Print file with 'pr' format (prettyprint) */
+         case 'r' : /* File to print with FORTRAN carriage control */
+         case 't' : /* Print troff output file */
+         case 'v' : /* Print raster file */
+            /*
+             * Verify that we have a username...
+             */
+
+             if (!user[0])
+             {
+               status = 1;
+               break;
+             }
+
+             /*
+             * Figure out which file we are printing...
+             */
+
+             for (i = 0; i < num_data; i ++)
+               if (strcmp(data[i], line + 1) == 0)
+                 break;
+
+              if (i >= num_data)
+             {
+               status = 1;
+               break;
+             }
+
+             /*
+             * Build an IPP_PRINT_JOB request...
+             */
+
+              if ((request = ippNew()) == NULL)
+             {
+               status = 1;
+               break;
+             }
+
+             request->request.op.operation_id = IPP_PRINT_JOB;
+              request->request.op.request_id   = 1;
+
+              snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s",
+                      cupsServer(), ippPort(), dest);
+
+             ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                          "attributes-charset", NULL,
+                          cupsLangEncoding(language));
+
+             ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                          "attributes-natural-language", NULL,
+                          language != NULL ? language->language : "C");
+
+             ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                          "printer-uri", NULL, uri);
+
+             if (line[0] == 'l')
+               ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+                            "document-format", NULL, "application/vnd.cups-raw");
+             else
+               ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+                            "document-format", NULL, "application/octet-stream");
+
+             ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                          "requesting-user-name", NULL, user);
+
+             if (title[0])
+               ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                            "job-name", NULL, title);
+
+             if (docname[0])
+               ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                            "document-name", NULL, docname);
+
+              if (line[0] == 'p')
+               ippAddBoolean(request, IPP_TAG_JOB, "prettyprint", 1);
+
+              snprintf(filename, sizeof(filename), "%s/%06d-%d", tmpdir,
+                      getpid(), i + 1);
+
+             /*
+             * Do the request...
+             */
+
+             snprintf(uri, sizeof(uri), "/printers/%s", dest);
+
+             if ((response = cupsDoFileRequest(http, request, uri, filename)) == NULL)
+               status = 1;
+             else if (response->request.status.status_code > IPP_OK_CONFLICT)
+               status = 1;
+
+              if (response != NULL)
+               ippDelete(response);
+             break;
+       }
+
+       if (status)
+         break;
+      }
+
+      fclose(fp);
+      httpClose(http);
+      cupsLangFree(language);
+    }
+  }
+
+ /*
+  * Clean up all temporary files and return...
+  */
+
+  for (i = -1; i < num_data; i ++)
+  {
+    snprintf(filename, sizeof(filename), "%s/%06d-%d", tmpdir, getpid(), i + 1);
+    unlink(filename);
+  }
+
+  return (status);
+}
+
+
+/*
+ * 'send_short_state()' - Send the short queue state.
+ */
+
+int                                    /* O - Command status */
+send_short_state(const char *dest,     /* I - Destination */
+                 const char *list)     /* I - List of jobs or users */
+{
+  puts("Sorry, not yet implemented!");
+  return (1);
+}
+
+
+/*
+ * 'send_long_state()' - Send the long queue state.
+ */
+
+int                                    /* O - Command status */
+send_long_state(const char *dest,      /* I - Destination */
+                const char *list)      /* I - List of jobs or users */
+{
+  puts("Sorry, not yet implemented!");
+  return (1);
+}
+
+
+/*
+ * 'remove_jobs()' - Cancel one or more jobs.
+ */
+
+int                                    /* O - Command status */
+remove_jobs(const char *dest,          /* I - Destination */
+            const char *agent,         /* I - User agent */
+           const char *list)           /* I - List of jobs or users */
+{
+  return (1);
+}
+
+
+/*
+ * End of "$Id: cups-lpd.c,v 1.1 2000/04/19 21:26:00 mike Exp $".
+ */