///////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008 Mouton Gérard. Ce fichier une adaptation d'une partie des sources de cups
// (dossier cgi-bin) adaptées pour constituer une bibliothéque utilisable à partir de tcl.
// Ces sources étant sous licence GPL, cette bibliothèque est donc fournie sous la même
// licence GPL.
// Vous pouvez donc le redistribuer et/ou le modifier selon les termes de la GNU General 
// Public License (Licence Publique Générale GNU) telle qu'elle a été publiée par 
// la Free Software Foundation; soit la version 2 de la licence, soit (comme vous le souhaitez) 
// toute version ultérieure.
// Voir la GNU General Public License pour plus de détails.
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
//          résultat d'analyse des sources de cups et interrogations?
/*
Le pilote de périphérique d'une imprimante est représenté par un fichier .ppd.
A la création de l'imprimante une copie de ce fichier est placée dans etc/cups/ppd avec comme
  nom celui donné à l'imprimante (ex: epson.pdd), et ce fichier peut être consulté à l'aide
  d'une requête http.
Les fichiers .ppd sont formés pour un langage, celui-ci est inscrit dans le fichier par la
  rubrique 'LanguageVersion:' dont les valeurs sont: English, French, etc, ...
Avec Une requête au serveur CUPS_GET_PPDS pour obtenir les pilotes disponibles, le langage
  fourni est donné sur 2 caractères: en, fr, ...., et ce code n'est pas disponible dans les
  fichiers .ppd
La langue retournée avec la requête IPP_GET_PRINTER_ATTRIBUTES est toujours 'en' et n'a à
priori rien à voir avec celle du pilote. 

*/
/////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h>
#include <string.h>
#include <tcl.h> 
#include <cups/cups.h> 
#include <cups/language.h>

#include "config.h"

int cups (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);

int lpq (Tcl_Interp *interp);
int lprm ( Tcl_Interp *interp,char *destin, int jobid);
int cups_imprimantes(Tcl_Interp *interp);
int cups_etat (Tcl_Interp *interp, char *printer);
int cups_pdd(Tcl_Interp *interp, char *printer);
int cups_getDefaut(Tcl_Interp *interp);
int cups_test (Tcl_Interp *interp, char *imprimante);
int cups_uris(Tcl_Interp *interp);
int cups_marques(Tcl_Interp *interp);
int cups_pilotes(Tcl_Interp *interp, char *marque);
int ajoutImprimante (Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
int supImprimante (Tcl_Interp *interp, char *);
int executerRequete (Tcl_Interp *interp, char *imprimante, ipp_op_t op);
int setModeAdmin (Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
int getModeAdmin (Tcl_Interp *interp);
static const char * motPasse (const char *prompt);

char *mPasse;    // mot de passe administrateur
int tentatives;  // nombres de tentatives de demande de mot de passe par cupsd

/////////////////////////////////////////// 
int Tclcups_Init (Tcl_Interp *interp) { 

  mPasse=(char *) malloc(128);
  if (mPasse==NULL) exit(0);
  memcpy(mPasse,"\x0",1);
  if (Tcl_InitStubs(interp, "8.1", 0) == 0L) {
    return TCL_ERROR;
  }
  Tcl_CreateObjCommand (interp, "cups", cups, (ClientData) NULL, NULL);

  //Tcl_CreateObjCommand (interp, "cups_lpq", lpq, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_lprm", lprm, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_imprimantes", cups_imprimantes, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_etat", cups_etat, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_pdd", cups_pdd, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_getDefaut", cups_getDefaut, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_setDefaut", cups_setDefaut, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_setTravaux", cups_setTravaux, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_setMarcheArret", cups_setMarcheArret, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_test", cups_test, (ClientData) NULL, NULL);

  //Tcl_CreateObjCommand (interp, "cups_uris", cups_uris, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_marques", cups_marques, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_pilotes", cups_pilotes, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_ajoutImprimante", ajoutImprimante, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_supImprimante", supImprimante, (ClientData) NULL, NULL);

  //Tcl_CreateObjCommand (interp, "cups_setModeAdmin", setModeAdmin, (ClientData) NULL, NULL);
  //Tcl_CreateObjCommand (interp, "cups_getModeAdmin", getModeAdmin, (ClientData) NULL, NULL);
  Tcl_PkgProvide(interp, "tclcups", "0.1");

  return TCL_OK; 
  } 
////////////////////////////////////////
void  Tclcups_Fini(ClientData clientData) {
//---------------------------------------
if (mPasse!=NULL) free(mPasse);
}
//////////////////////////////////////////////////////
int cups (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])  {
//----------------------------------------------------
char *cmde;
char *imp;
char *marque;
int id;
int rep;

if (objc < 2) {
  Tcl_WrongNumArgs(interp, 1, objv, "cups operation ?arg arg ...?");
  return TCL_ERROR;
  }

cmde=Tcl_GetString (objv[1]);
if (strcmp(cmde,"lpq")==0 ) rep=lpq(interp);
else if (strcmp(cmde,"lprm")==0 ) {
  if (objc < 4) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups lprm imprimante id");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    Tcl_GetIntFromObj(interp, objv[3], &id);
    rep=lprm(interp,imp,id);   
    }
  }
else if (strcmp(cmde,"imprimantes")==0 ) rep=cups_imprimantes(interp);
else if (strcmp(cmde,"etat")==0 ) {
  if (objc < 3) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups etat imprimante");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    rep=cups_etat(interp,imp);
    }
  }
else if (strcmp(cmde,"pdd")==0 ) {
  if (objc < 3) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups pdd imprimante");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    rep=cups_pdd(interp,imp);
    }
  }
else if (strcmp(cmde,"getDefaut")==0 ) rep=cups_getDefaut(interp);
else if (strcmp(cmde,"setDefaut")==0 ) {
  if (objc < 3) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups setDefaut imprimante");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    rep=executerRequete(interp, imp, CUPS_SET_DEFAULT);
    }
  }
else if (strcmp(cmde,"setTravaux")==0 ) {
  if (objc < 4) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups setTravaux imprimante mode");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    Tcl_GetIntFromObj(interp, objv[3], &id);
    if (id==0) rep=executerRequete(interp, imp, CUPS_REJECT_JOBS);
    else rep=executerRequete(interp, imp, CUPS_ACCEPT_JOBS);
    }
  }
else if (strcmp(cmde,"setMarcheArret")==0 ) {
  if (objc < 4) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups setMarcheArret imprimante mode");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    Tcl_GetIntFromObj(interp, objv[3], &id);
    if (id==0) rep=executerRequete(interp, imp, IPP_PAUSE_PRINTER);
    else rep=executerRequete(interp, imp, IPP_RESUME_PRINTER);
    }
  }
else if (strcmp(cmde,"test")==0 ) {
  if (objc < 3) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups test imprimante");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    rep=cups_test(interp,imp);
    }
  }
else if (strcmp(cmde,"uris")==0 ) rep=cups_uris(interp);
else if (strcmp(cmde,"marques")==0 ) rep=cups_marques(interp);
else if (strcmp(cmde,"pilotes")==0 ) {
  if(objc<4) marque=NULL; 
  else marque=Tcl_GetString (objv[3]);
  //printf("cups: objc=%d marque=%s\n",objc,marque);  
  rep=cups_pilotes(interp,marque);
  }

else if (strcmp(cmde,"ajoutImprimante")==0 ) {
  if (objc < 7) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups ajoutImprimante -p nom_imprimante -L emplacement -D description -v périphérique -m ppd");
    rep=TCL_ERROR;
    }
  else {
    rep=ajoutImprimante(interp,objc,objv);
    }
  }
else if (strcmp(cmde,"supImprimante")==0 ) {
  if (objc < 3) {
    Tcl_WrongNumArgs(interp, 1, objv, "cups supImprimante imprimante");
    rep=TCL_ERROR;
    }
  else {
    imp=Tcl_GetString (objv[2]);
    rep=supImprimante(interp,imp);
    }
  }
else if (strcmp(cmde,"setModeAdmin")==0 ) {
  rep=setModeAdmin(interp,objc,objv);
  }
else if (strcmp(cmde,"getModeAdmin")==0 ) rep=getModeAdmin(interp);
else {
  Tcl_WrongNumArgs(interp, 1, objv, "operation non conforme");
  return TCL_ERROR;


  }

return rep;
}

//////////////////////////////////////////////
int lpq (Tcl_Interp *interp)  {
//--------------------------------------------
int        i; 
int        num_jobs; 
time_t     t1;
struct tm  *loctime; 
char buffer[128]; 

cups_job_t *jobs; 
 
Tcl_Obj *resultObjPtr;
Tcl_Obj *elem;
Tcl_Obj *objPtr;

resultObjPtr=Tcl_NewListObj(0,NULL);
elem=Tcl_NewListObj(0,NULL);
objPtr= Tcl_NewStringObj(NULL,0);


// Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewIntObj(rang));
//   objPtr= Tcl_NewStringObj(nomElement(dataPtr,rang),-1);
//   Tcl_ListObjAppendElement(interp, resultObjPtr, objPtr);

num_jobs = cupsGetJobs(&jobs, NULL, 0, 0); 
 
//printf("%d active job(s): %d\n", num_jobs,IPP_JOB_COMPLETED); 
for (i = 0; i < num_jobs; i ++) { 
  //printf("%-16.16s %-6d %-12.12s %s (%s)\n", jobs[i].dest, jobs[i].id, 
  //       jobs[i].user, jobs[i].title, 
  //       jobs[i].state != IPP_JOB_PENDING ? "printing" : "pending"); 
 
  elem=Tcl_NewListObj(0,NULL);

  Tcl_ListObjAppendElement(interp, elem, Tcl_NewIntObj(jobs[i].id));

  objPtr= Tcl_NewStringObj( jobs[i].dest,-1);
  Tcl_ListObjAppendElement(interp, elem,objPtr);

  objPtr= Tcl_NewStringObj( jobs[i].user,-1);
  Tcl_ListObjAppendElement(interp, elem,objPtr);

  objPtr= Tcl_NewStringObj( jobs[i].title,-1);
  Tcl_ListObjAppendElement(interp, elem,objPtr);

  Tcl_ListObjAppendElement(interp, elem, Tcl_NewIntObj(jobs[i].size));

  loctime = localtime (&jobs[i].creation_time); 
  strftime (buffer, 128, "%d/%m/%Y %H:%M", loctime); 
  objPtr= Tcl_NewStringObj( buffer,-1);
  Tcl_ListObjAppendElement(interp, elem,objPtr);

  Tcl_ListObjAppendElement(interp, elem, Tcl_NewIntObj(jobs[i].state));

  Tcl_ListObjAppendElement(interp, resultObjPtr, elem);
  } 
cupsFreeJobs(num_jobs, jobs); 

Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK; 
} 

/////////////////////////////////////////////////////////////////
int lprm ( Tcl_Interp *interp,char *destin, int jobid)  {
//--------------------------------------------------------------
// Suppression travail impression 
// argv[1]= nom (destination)
// argv[2]= id
//--------------------------------------------------------------
int status; 
Tcl_Obj *resultObjPtr;

//Tcl_GetIntFromObj(interp, objv[2], &jobid);
//  printf("jobid=%d dest=%s\n",jobid, Tcl_GetString (objv[1]));
status = cupsCancelJob( destin, jobid); 

resultObjPtr=Tcl_NewIntObj(status);
Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;
}

////////////////////////////////////////////////////////////////
int setModeAdmin (Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])  {
//--------------------------------------------------------------
// Se place en mode administrateur afin de pouvoir réaliser certaines
// opération telles que supprimer, ajouter imprimante, ...
// Uniquement necessaire pour les utilisateurs non 'root'
// Le mot de passe 'root est donné en argument.
// Retourne:
// 0=échec (mot de passe invalide)
// 1=succés (utilisteur root ou mot de passe valide)
//-----------------------------------------------------------------
http_t	*http;		
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
char    uri[HTTP_MAX_URI];      /* Printer URI */

static const char *def_attrs[] = {
  "printer-name",
  "printer-uri-supported"
  };
Tcl_Obj *resultObjPtr;
int rep;
   
// valeurs défaut   
rep=0;   
//memcpy(mPasse,"\x0",1);

http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());

if (strcmp(cupsUser(),"root")!=0 ) {
  // enregistrement du mot de passe
  if (objc>2) sprintf(mPasse,"%s",Tcl_GetString(objv[2]));
  // Si utilisateur non root (au niveau cupsd), on se met en 'root'
  cupsSetUser("root");
  // on demande à cupsd  d'appeler la fonction 'motPasse' lorsqu'il
  // aura besoin d'un commpte 'administrateur'. 
  tentatives=0;
  cupsSetPasswordCB(motPasse);
  // on lance une requête CUPS_GET_DEFAULT avec uri=/admin, afin
  // que cups ait besoin d'un compte aDministrateur

  request = ippNew();
  request->request.op.operation_id = CUPS_GET_DEFAULT;
  request->request.op.request_id   = 1;
  language = cupsLangDefault();
  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->language);
  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
    "requested-attributes", sizeof(def_attrs) / sizeof(def_attrs[0]), NULL, def_attrs);


  if ((response = cupsDoRequest(http, request, "/admin")) != NULL)  {
    // succés, le mot de passe est valide
    rep=1;
    ippDelete(response);
    }  
  else {
    // echec, mot de passe invalide, on l'annule.
    rep=0;
    memcpy(mPasse,"\x0",1);
    }
  }
// utilisateur 'root', pas besoin de mot de passe  
else rep=1; 

// Remise de l'utilisateur d'origine
cupsSetUser(NULL);
httpClose(http);
cupsLangFree(language);

resultObjPtr=Tcl_NewIntObj(rep);
Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;
}
//////////////////////////////////////////////////
int getModeAdmin (Tcl_Interp *interp)  {
//------------------------------------------------
// Vérifie si en mode administrateur
// Retourne:
// 0 = non
// 1 = oui
//-------------------------------------------------
Tcl_Obj *resultObjPtr;
int rep;

rep=1;
if (strcmp(cupsUser(),"root")!=0 ) {
  if (strlen(mPasse)==0) rep=0;
  }
resultObjPtr=Tcl_NewIntObj(rep);
Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;

}

/////////////////////////////////////////////////
int cups_imprimantes (Tcl_Interp *interp)  {
//------------------------------------------------
// liste des imprimantes
//------------------------------------------------
int n,  nimp;
cups_dest_t *dests; 
Tcl_Obj *objPtr;
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewListObj(0,NULL);
nimp = cupsGetDests(&dests); 
for (n=0;n<nimp;n++) {
  objPtr= Tcl_NewStringObj(dests[n].name,-1);
  Tcl_ListObjAppendElement(interp, resultObjPtr, objPtr);
  }

cupsFreeDests(nimp, dests); 
Tcl_SetObjResult(interp, resultObjPtr);

return TCL_OK;
}

////////////////////////////////////////////////////////
int cups_etat (Tcl_Interp *interp, char *printer)  {
//------------------------------------------------------
// Retourne l'état d'une imprimante sous forme de liste. Eléments:
// nom
// description
// emplacement
// modele (pilote périphérique)
// device-uri
// état (3=au repos 4=processing 5=arretée)
// message état
// raison état
// accepte travaux (0=rejet 1=accepte)
//--------------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_attribute_t *attr;		/* IPP attribute */
char    uri[HTTP_MAX_URI];      /* Printer URI */
http_t	*http;
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewListObj(0,NULL);

http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
if (http) { 
  // requête IPP_GET_PRINTER_ATTRIBUTES
  char *nom, *desc, *emp, *mod, *etatm, *etatr, *device;
  int etat, acc;

  request = ippNew();
  request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
  request->request.op.request_id   = 1;
  language = cupsLangDefault();
  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->language);

  //printer="epson";
  snprintf(uri, sizeof(uri), "ipp://%s/printers/%s", getenv("SERVER_NAME"), printer);
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);

  if ((response = cupsDoRequest(http, request, "/")) != NULL)  {
    attr = response->attrs;
    for (attr = response->attrs; attr != NULL;) {
      //  printf("nomattr=%s num_values=%d\n",attr->name,attr->num_values);
      if (strcmp(attr->name,"printer-name")==0 ) nom =attr->values[0].string.text;
      else if (strcmp(attr->name,"printer-info")==0 ) desc =attr->values[0].string.text;
      else if (strcmp(attr->name,"printer-location")==0 ) emp =attr->values[0].string.text;
      else if (strcmp(attr->name,"printer-make-and-model")==0 ) mod =attr->values[0].string.text;
      else if (strcmp(attr->name,"device-uri")==0 ) device=attr->values[0].string.text;
      else if (strcmp(attr->name,"printer-state")==0 ) etat =attr->values[0].integer;
      else if (strcmp(attr->name,"printer-state-message")==0 ) etatm =attr->values[0].string.text;
      else if (strcmp(attr->name,"printer-state-reasons")==0 ) etatr =attr->values[0].string.text;
      else if (strcmp(attr->name,"printer-is-accepting-jobs")==0 ) acc =(int) attr->values[0].boolean;
   
      // si plusieurs valeurs, explorer avec      
      //for (i = 0; i < attr->num_values; i ++) val=attr->values[i].string.text
      
      attr = attr->next;
      }
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(nom,-1));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(desc,-1));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(emp,-1));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(mod,-1));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(device,-1));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewIntObj(etat));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(etatm,-1));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(etatr,-1));
    Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewIntObj(acc));
 
    ippDelete(response);
    }
  cupsLangFree(language);
  httpClose(http);
  }
else printf("Connexion au serveur cups impossible\n");   
  
Tcl_SetObjResult(interp, resultObjPtr);

return TCL_OK;

}
////////////////////////////////////////////////////////////
int cups_pdd (Tcl_Interp *interp, char *printer)  {
//--------------------------------------------------------------
// Retourne caractéristiques d'une imprimante données par son fichier .pdd
// Eléments:
// - modele
// - manufacture
// - nickname
// - langue (fr, en, ...)
//---------------------------------------------------------------
http_t	*http;
char  uri[HTTP_MAX_URI];
int   fd;                 /* PPD file */
char  filename[1024];     /* PPD filename */
char  buffer[1024];       /* Buffer */
int   bytes;              /* Number of bytes */
ppd_file_t *ppd;          /* PPD information */
char lge[4];
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewListObj(0,NULL);

http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
if (http) { 
  snprintf(uri, sizeof(uri), "/printers/%s.ppd", printer);
  if (httpGet(http, uri))  httpGet(http, uri);

  while (httpUpdate(http) == HTTP_CONTINUE);
  if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0) {
    while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0)
        write(fd, buffer, bytes);
    close(fd);
    if ((ppd = ppdOpenFile(filename)) != NULL) {

      if (ppd->modelname) {
        Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(ppd->modelname,-1));
        }
      else Tcl_ListObjAppendElement(interp, resultObjPtr, NULL);
      if (ppd->manufacturer) {
        Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(ppd->manufacturer,-1));
        }
      else Tcl_ListObjAppendElement(interp, resultObjPtr, NULL);
      if (ppd->nickname) {
        Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(ppd->nickname,-1));
        }
      else Tcl_ListObjAppendElement(interp, resultObjPtr, NULL);
      if (ppd->lang_version) {
        snprintf(lge,3,"%s",ppd->lang_version);
        lge[0]=tolower(lge[0]);
        lge[1]=tolower(lge[1]);
        Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(lge,-1));
        }
      else Tcl_ListObjAppendElement(interp, resultObjPtr, NULL);
      ppdClose(ppd);
      }
    unlink(filename);
    }
  }
else printf("Connexion au serveur cups impossible\n");   
  
Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;
}
/////////////////////////////////////////////////////////
int cups_getDefaut (Tcl_Interp *interp)  {
//--------------------------------------------------------
// Retourne l'imprimante par defaut
//---------------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_attribute_t *attr;		/* IPP attribute */
static const char *def_attrs[] =  /* Attributes for default printer */
  {
  "printer-name",
  "printer-uri-supported"
  };

char    *printer;    
http_t	*http;
Tcl_Obj *resultObjPtr;
resultObjPtr=Tcl_NewStringObj(NULL,0);

printer=NULL;
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());

if (http) { 
  request = ippNew();
  request->request.op.operation_id = CUPS_GET_DEFAULT;
  request->request.op.request_id   = 1;
  language = cupsLangDefault();
  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->language);
  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
    "requested-attributes",
    sizeof(def_attrs) / sizeof(def_attrs[0]), NULL, def_attrs);

  if ((response = cupsDoRequest(http, request, "/")) != NULL)  {
    attr = response->attrs;
    for (attr = response->attrs; attr != NULL;) {
      //  printf("nomattr=%s num_values=%d\n",attr->name,attr->num_values);
      if (strcmp(attr->name,"printer-name")==0 ) {
        printer =attr->values[0].string.text;
        break;
        }
      attr = attr->next;
      }
    Tcl_AppendStringsToObj(resultObjPtr, printer, NULL);
    //resultObjPtr=Tcl_NewStringObj(printer,-1);
    ippDelete(response);
    }  
  httpClose(http);
  cupsLangFree(language);
  }
Tcl_SetObjResult(interp, resultObjPtr);

return TCL_OK;
}


////////////////////////////////////////////////////////
int cups_test (Tcl_Interp *interp, char *imprimante)  {
//------------------------------------------------------
// Envoi d'une page de test à une imprimante
//---------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_status_t  status;           /* Operation status... */
char    uri[HTTP_MAX_URI];      /* Printer URI */
http_t	*http;
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewStringObj(NULL,0);

http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
if (http) {
  language = cupsLangDefault();
  snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", imprimante);
  request = ippNew();
  request->request.op.operation_id = IPP_PRINT_JOB;
  request->request.op.request_id   = 1;

  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->language);
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);

  if (getenv("USER") != NULL)
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, getenv("USER"));
  else
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, "root");

  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, "Test Page");
  ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
        	 NULL, "application/postscript");
  if ((response = cupsDoFileRequest(http, request, uri + 15,
                                      CUPS_DATADIR "/data/testprint.ps")) != NULL)
    {
    status = response->request.status.status_code;
    ippDelete(response);
    }
  else status = cupsLastError();
  if (status > IPP_OK_CONFLICT)  {
    Tcl_AppendStringsToObj(resultObjPtr, ippErrorString(status), NULL);
    }
  httpClose(http);
  cupsLangFree(language);
  }   
Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;
}

////////////////////////////////////////////////////////
int cups_uris (Tcl_Interp *interp)  {
//------------------------------------------------------
// Retourne la liste des uri disponibles
//------------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_attribute_t *attr;		/* IPP attribute */

http_t	*http;
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewListObj(0,NULL);
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());

request = ippNew();
request->request.op.operation_id = CUPS_GET_DEVICES;
request->request.op.request_id   = 1;
language = cupsLangDefault();
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->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
                 NULL, "ipp://localhost/printers/");


if ((response = cupsDoRequest(http, request, "/")) != NULL)  {
  attr = response->attrs;
  for (attr = response->attrs; attr != NULL;) {
    //  printf("nomattr=%s num_values=%d\n",attr->name,attr->num_values);
    if (attr->num_values>0) {
      if (strcmp(attr->name,"device-info")==0 ) {
        Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(attr->values[0].string.text,-1));
        }
      if (strcmp(attr->name,"device-uri")==0 ) {
        Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(attr->values[0].string.text,-1));
        }
      }

    attr = attr->next;
    }
  ippDelete(response);

  }  
httpClose(http);
cupsLangFree(language);
  
Tcl_SetObjResult(interp, resultObjPtr);

return TCL_OK;

}

////////////////////////////////////////////////////////
int cups_marques (Tcl_Interp *interp)  {
//------------------------------------------------------
// Retourne la liste des marques d'imprimantes
//------------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_attribute_t *attr;		/* IPP attribute */
char *txt, *rech;
int lg;
http_t	*http;
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewListObj(0,NULL);
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());

request = ippNew();
request->request.op.operation_id = CUPS_GET_PPDS;
request->request.op.request_id   = 1;
language = cupsLangDefault();
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->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
                 NULL, "ipp://localhost/printers/");

if ((response = cupsDoRequest(http, request, "/")) != NULL)  {
  txt=(char *) malloc(4096);
  if (txt==NULL) return -1;
  rech=(char *) malloc(256);
  memcpy(txt,"\x0",1);
  attr = response->attrs;
  
  for (attr = response->attrs; attr != NULL;) {
    //printf("nomattr=%s num_values=%d\n",attr->name,attr->num_values);
    if ( attr->num_values>0 && strcmp(attr->name,"ppd-make")==0 ) {
      sprintf(rech,"#¤%s",attr->values[0].string.text);
      if (strcasestr(txt,rech) == 0 )
        {
        lg=strlen(txt);
        if (lg<4000) sprintf(txt+lg,"%s",rech);
        Tcl_ListObjAppendElement(interp, resultObjPtr, Tcl_NewStringObj(attr->values[0].string.text,-1));
        }
      }
    attr = attr->next;
    }
  ippDelete(response);
  free(txt);
  free(rech);
  }  
httpClose(http);
cupsLangFree(language);

Tcl_SetObjResult(interp, resultObjPtr);

return TCL_OK;
}

////////////////////////////////////////////////////////////
int cups_pilotes (Tcl_Interp *interp, char *marque)  {
//----------------------------------------------------------
// Retourne la liste des pilotes d'imprimantes disponibles
// Si marque=NULL, liste pour toutes les marques sinon selection 
// de la marque 'marque".
// Chaque élément contient:
// - fichier .ppd
// - marque
// - modele
// - langage
//----------------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_attribute_t *attr;		/* IPP attribute */
http_t	*http;
int lg;
int accepte;

//printf("cups_pilotes: marque=%s\n",marque);
Tcl_Obj *elem;
Tcl_Obj *resultObjPtr;

elem=Tcl_NewListObj(0,NULL);
resultObjPtr=Tcl_NewListObj(0,NULL);
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());

request = ippNew();
request->request.op.operation_id = CUPS_GET_PPDS;
request->request.op.request_id   = 1;
language = cupsLangDefault();
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->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
                 NULL, "ipp://localhost/printers/");

if ((response = cupsDoRequest(http, request, "/")) != NULL)  {
  //if (objc>2) {
  //  marque= Tcl_GetStringFromObj(objv[2],&lg);
  //  }
  //else marque=NULL;  
  accepte=1;
  
  attr = response->attrs;
  for (attr = response->attrs; attr != NULL;) {
    if ( attr->num_values>0) {
      //printf("nomattr=%s num_values=%d text=%s\n",attr->name,attr->num_values,attr->values[0].string.text);
      if ( attr->num_values>0 && strcmp(attr->name,"ppd-name")==0 ) {
        elem=Tcl_NewListObj(0,NULL);
        Tcl_ListObjAppendElement(interp, elem, Tcl_NewStringObj(attr->values[0].string.text,-1));
        }
      else if (strcmp(attr->name,"ppd-make")==0 ) {
        Tcl_ListObjAppendElement(interp, elem, Tcl_NewStringObj(attr->values[0].string.text,-1));
        if ( marque!=NULL && strcasecmp(attr->values[0].string.text,marque)!=0 ) accepte=0;
        else accepte=1;
        }
      else if ( attr->num_values>0 && strcmp(attr->name,"ppd-make-and-model")==0 ) {
        Tcl_ListObjAppendElement(interp, elem, Tcl_NewStringObj(attr->values[0].string.text,-1));
        }
      else if ( attr->num_values>0 && strcmp(attr->name,"ppd-natural-language")==0 ) {
        if (accepte ==1) {
          Tcl_ListObjAppendElement(interp, elem, Tcl_NewStringObj(attr->values[0].string.text,-1));
          Tcl_ListObjAppendElement(interp, resultObjPtr, elem);
          }
        }
      }  
    attr = attr->next;
    }
  ippDelete(response);
  }  
httpClose(http);
cupsLangFree(language);

Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;
}

////////////////////////////////////////////////////////////////
int ajoutImprimante (Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])  {
//--------------------------------------------------------------
// Ajout d'une imprimante. Arguments:
// -p nom imprimante 
// -L emplacement
// -D description
// -v périphérique 
// -m ppd 
//--------------------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_attribute_t *attr;		/* IPP attribute */
char  uri[HTTP_MAX_URI];        /* Device or printer URI */
ipp_status_t   status;          /* Request status */
http_t	*http;
int n;
char *ptr;
char *nom, *periph, *pilote, *desc, *emplacement;
Tcl_Obj *resultObjPtr;

nom=NULL;
periph=NULL;
pilote=NULL;
desc=NULL;
emplacement=NULL;

if (strcmp(cupsUser(),"root")!=0 ) {
  cupsSetUser("root");
  tentatives=0;
  cupsSetPasswordCB(motPasse);
  }

resultObjPtr=Tcl_NewStringObj(NULL,0);

for (n=2;n<objc-1;n=n+2) {
  ptr=Tcl_GetString(objv[n]);
  //printf("ptr=%s objv=%s\n",ptr, Tcl_GetString(objv[n+1])); 
  if (strcmp(ptr,"-p")==0 ) nom=Tcl_GetString(objv[n+1]);
  if (strcmp(ptr,"-v")==0 ) periph=Tcl_GetString(objv[n+1]);
  if (strcmp(ptr,"-m")==0 ) pilote=Tcl_GetString(objv[n+1]);
  if (strcmp(ptr,"-L")==0 ) emplacement=Tcl_GetString(objv[n+1]);
  if (strcmp(ptr,"-D")==0 ) desc=Tcl_GetString(objv[n+1]);
  }
//printf("ajoutImrimante: nom=%s emplacement=%s desc=%s\n",nom,emplacement,desc);

if (nom==NULL || periph==NULL || pilote==NULL) {
  printf("manque option -p, -v ou -m\n");
  return TCL_OK;
  }
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
if (http) {
  request = ippNew();
  request->request.op.operation_id = CUPS_ADD_PRINTER;
  request->request.op.request_id   = 1;
  language = cupsLangDefault();

  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->language);

  snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", nom);
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
  ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",NULL,emplacement);
  ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",NULL, desc);
  ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", NULL, pilote);
  ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, periph);
  ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
  ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",IPP_PRINTER_IDLE);

  //printf("nom=%s emp=%s desc=%s pilote=%s periph=%s\n",nom,emplacement,desc,pilote,periph);

  if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
    {
    status = response->request.status.status_code;
    ippDelete(response);
    }
  else {
    status = cupsLastError();
    }

  if (status > IPP_OK_CONFLICT)  {
    Tcl_AppendStringsToObj(resultObjPtr, ippErrorString(status), NULL);
    //printf("erreur=%s\n", ippErrorString(status));
    }
  httpClose(http);
  cupsLangFree(language);
  }
cupsSetUser(NULL);
Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;
}

////////////////////////////////////////////////////////////
int supImprimante (Tcl_Interp *interp, char *printer)  {
//----------------------------------------------------------
// Suppression d'une imprimante.
//----------------------------------------------------------
ipp_t         *request;          /* IPP request */
ipp_t         *response;         /* IPP response */
char          uri[HTTP_MAX_URI]; /* Job URI */
cups_lang_t   *language = NULL;  /* Default language */
ipp_status_t  status;            /* Operation status... */
http_t	*http;
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewStringObj(NULL,0);

// besoin d'un accés administrateur
tentatives=0;
if (strcmp(cupsUser(),"root")!=0 ) {
  cupsSetUser("root");
  tentatives=0;
  cupsSetPasswordCB(motPasse);
  }

//printf("SUP: printer=%s user=%s passe=%s\n",printer,cupsUser(),mPasse);

http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
if (http) {
  snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
  language = cupsLangDefault();
  request = ippNew();
  request->request.op.operation_id = CUPS_DELETE_PRINTER;
  request->request.op.request_id   = 1;
  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->language);
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
               NULL, uri);

 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
   status = response->request.status.status_code;
   ippDelete(response);
   }
  else status = cupsLastError();

  if (status > IPP_OK_CONFLICT) {
    Tcl_AppendToObj(resultObjPtr,ippErrorString(status),-1);
    }
  httpClose(http);
  cupsLangFree(language);
  }
Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;

}
//////////////////////////////////////////////////////////////////
int executerRequete (Tcl_Interp *interp, char *imprimante, ipp_op_t op)  {
//--------------------------------------------------------------
// Execution d'une requete concernant  une imprimante
//--------------------------------------------------------------
ipp_t        *request = NULL;   /* IPP Request */
ipp_t        *response = NULL;  /* IPP Response */
cups_lang_t  *language = NULL;  /* Default language */
ipp_attribute_t *attr;		/* IPP attribute */
ipp_status_t  status;           /* Operation status... */
char    uri[HTTP_MAX_URI];      /* Printer URI */
http_t	*http;
Tcl_Obj *resultObjPtr;

resultObjPtr=Tcl_NewStringObj(NULL,0);

// besoin d'un accés administrateur
tentatives=0;
if (strcmp(cupsUser(),"root")!=0 ) {
  cupsSetUser("root");
  tentatives=0;
  cupsSetPasswordCB(motPasse);
  }

http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());

if (http) { 
  snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", imprimante);
  request = ippNew();
  request->request.op.operation_id = op;
  request->request.op.request_id   = 1;
  language = cupsLangDefault();

  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->language);
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);

  if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)  {
    status = response->request.status.status_code;
    ippDelete(response);
    }
  else status = cupsLastError();

  if (status > IPP_OK_CONFLICT) {
    Tcl_AppendStringsToObj(resultObjPtr, ippErrorString(status), NULL);
    }
    
  httpClose(http);
  cupsLangFree(language);
  }  

Tcl_SetObjResult(interp, resultObjPtr);
return TCL_OK;
}

//=================================================
static const char * motPasse (const char *prompt) {
//-------------------------------------------------
// Fonction appelée lorsque le serveur cupsd a besoin d'un 
// compte et mot de passe pour effectuer une requête.
// Le serveur fait appel jusqu'a ce que le mot de passe soit 
// valide ou NULL.
// C'est la fonction 'cupsSetPasswordCB' qui indique au serveur 
// cette fonction a appeler pour obtenir un mot de passe.
//-----------------------------------------------------
//printf("dmde=%d pronmpt=%s\n",dmde,prompt);
tentatives++;
if (tentatives<2) {
  //printf("motPasse: tentative=%d mPasse=%s\n",tentatives,mPasse);
  return mPasse;
  }
else return NULL;

}



