/*  --------------------------------------------------------
 ** 
 ** File: davlib.c - WebDAV module
 **
 ** This file implements the WebDAV functions for Amaya editor.
 **
 ** Author : Manuele Kirsch Pinheiro
 ** Email: Manuele.Kirsch_Pinheiro@inrialpes.fr / manuele@inf.ufrgs.br 
 ** Project CEMT - II/UFRGS - Opera Group/INRIA
 ** Financed by CNPq(Brazil)/INRIA(France) Cooperation
 **
 ** Date : April / 2002
 **
 ** $Id: davlib.c,v 1.10 2002/07/01 10:34:16 kahan Exp $
 ** $Date: 2002/07/01 10:34:16 $
 ** $Log: davlib.c,v $
 ** Revision 1.10  2002/07/01 10:34:16  kahan
 ** JK: Enabling/Disabling DAV support by means of the new DAV_Enable
 ** registry entry.
 ** Removed the DAV menu from the standard profile.
 **
 ** Revision 1.9  2002/06/13 16:10:13  kirschpi
 ** New dialogue "WebDAV Preferences"
 ** Corrections due last commit by JK
 ** Manuele
 **
 ** Revision 1.8  2002/06/13 13:40:32  kahan
 ** JK: Changed MAX_LINE to DAV_MAX_LINE. MAX_LINE is a reserved macro and
 ** the code was generating a warning.
 **
 ** Revision 1.7  2002/06/11 17:34:52  kirschpi
 ** improving commentaries and format (for WebDAV code).
 ** update DAV Resources list automatically
 ** Manuele
 **
 ** Revision 1.6  2002/06/06 17:10:45  kirschpi
 ** Breaking the user messages in three lines
 ** Fixing some code format problems
 ** Fixing DAVLockIndicator, when Lock discovery is disabled.
 ** Fixing unecessary memory allocations in FilterMultiStatus_handler
 ** and FilterLocked_handler.
 ** Manuele
 **
 ** Revision 1.5  2002/06/05 16:46:06  kirschpi
 ** Applying Amaya code format.
 ** Modifying some dialogs (looking for a better windows presentation)
 ** Adding a DAVResource list, a list of resources (specially collections),
 ** where we should do a Lock discovery.
 ** Manuele
 **
 ** Revision 1.4  2002/06/04 14:51:41  kirschpi
 ** Fixing bug on InitDAV.
 ** Manuele
 **
 ** Revision 1.3  2002/06/03 14:37:42  kirschpi
 ** The name of some public functions have been changed to avoid conflic with
 ** other libraries.
 **
 ** Revision 1.2  2002/05/31 17:59:19  kirschpi
 ** Functions to give to user some informations about active locks
 ** (a basic awareness support) when the user load or exit a document.
 **
 * -------------------------------------------------------- 
 */

#include <stdlib.h>
#include <stdio.h>

#define THOT_EXPORT extern

#include "davlib.h"

#include "davlib_f.h"
#include "query_f.h"
#include "init_f.h"
#include "AHTURLTools_f.h"

#include "davlibCommon_f.h"
#include "davlibRequests_f.h"
#include "davlibUI_f.h"


/* ********************************************************************* *
 *                               INIT FUNCTION                           *
 * ********************************************************************* */


/*----------------------------------------------------------------------
   InitDAV - initialization function. Inits DAVHome variable pointing to
             home dir, where the lock base will be stored.   
  ----------------------------------------------------------------------*/
void InitDAV (void) 
{
    char *ptr = NULL;
    BOOL modified = FALSE;
    char *fqdn = NULL;
    char *email = NULL;

    /* check if DAV support is enabled */
    TtaGetEnvBoolean ("DAV_ENABLE", &DAVLibEnable);
    if (!DAVLibEnable)
      return;

    /* ******************** DAVHome ********************* */
    /* try to get default home (.amaya) dir from APP_HOME */
    ptr = TtaGetEnvString ("APP_HOME");
    sprintf (DAVHome,"%s%c",(ptr)?ptr:TempFileDirectory,DIR_SEP);

#ifdef DEBUG_DAV
    fprintf (stderr,"InitDAV..... DAVHome is %s\n",DAVHome);
#endif   

    
    /* **************** DAVFullHostName ***************** */
    fqdn = DAVFQDN();
    sprintf (DAVFullHostName,"%s",fqdn);
    
#ifdef DEBUG_DAV
    fprintf (stderr,"InitDAV..... DAVFullHostName is %s\n",DAVFullHostName);
#endif   

    
    /***** DAVUserURL, DAVLockScope, DAVDepth, DAVTimeout *****/

    /* getting user URL: if no DAV_USER_URL element defined in 
     * thot.rc, get the user email */
    ptr = NULL; 
    ptr = TtaGetEnvString (DAV_USER_URL);
    if (ptr && (*ptr))   
        sprintf (DAVUserURL,ptr);
    else 
     {  
        email = DAVDefaultEmail();
        sprintf (DAVUserURL,"%s%s",(email)?"mailto:":"http://", (email)?email:fqdn);

        /* save user URL in thot env */
        TtaSetEnvString (DAV_USER_URL,DAVUserURL,TRUE);
        modified = TRUE;
     }
    

    /* getting lock scope. If there is an entry DAV_LOCK_SCOPE in
     * thot.rc and it is valid, use it. Otherwise, assume "exclusive" scope */
    ptr = NULL; 
    ptr = TtaGetEnvString (DAV_LOCK_SCOPE);
    if (ptr && (*ptr) && 
       (!strcmp(ptr,"exclusive") || !strcmp (ptr,"shared")))
        sprintf (DAVLockScope,ptr);
    else 
     { 
        sprintf (DAVLockScope,"exclusive");
        
        /*save lock scope in thot env*/
        TtaSetEnvString (DAV_LOCK_SCOPE,DAVLockScope,TRUE);
        modified = TRUE;
     }

    
    /* getting depth option. If there is an entry DAV_DEPTH and
     * it is valid, use it/ Otherwise, assuming 0 
     * Note: for LOCK request, only the values 0 and infinity are accepted*/
    ptr = NULL;  
    ptr = TtaGetEnvString (DAV_DEPTH);
    if (ptr && (*ptr) &&\
       (!strcmp (ptr,"0") || !strcmp(ptr,"infinity")))
        sprintf (DAVDepth,ptr); 
    else 
     {
        sprintf (DAVDepth,"0");
        
        /* save depth in thot env */
        TtaSetEnvString (DAV_DEPTH,DAVDepth,TRUE);
        modified = TRUE;
     }

    
    /* getting timeout option. If no timeout,assuming Infinite */
    ptr = NULL; 
    ptr = TtaGetEnvString (DAV_TIMEOUT);
    if (ptr && (*ptr))
        sprintf (DAVTimeout,ptr);
    else
     { 
        sprintf (DAVTimeout,"Infinite");

        /* save timeout in thot env */
        TtaSetEnvString (DAV_TIMEOUT,DAVTimeout,TRUE);
        modified = TRUE;
     }

    
    /************* DAVAwareness, DAVAwarenessOnExit ************ */
    /* getting general option about awareness information */
    ptr = NULL;
    DAVAwareness = NO;
    ptr = TtaGetEnvString (DAV_AWARENESS);
    if (ptr && (*ptr)) 
     {
        if (!strcasecomp (ptr,"yes"))
            DAVAwareness = YES; 
     }
    else 
     {
        TtaSetEnvString (DAV_AWARENESS,"no",TRUE);
        modified = TRUE;
     }
    
    /* getting option about awareness information when exiting a resouce */
    ptr = NULL;
    DAVAwarenessExit = NO;
    ptr = TtaGetEnvString (DAV_AWARENESS_EXIT);
    if (ptr && (*ptr)) 
     {
        if (!strcasecomp (ptr,"yes"))
            DAVAwarenessExit = YES; 
     }    
    else
     {
        TtaSetEnvString (DAV_AWARENESS_EXIT,"no",TRUE);
        modified = TRUE;
     }
    
    
    /************************** DAVResources ******************** */
    ptr = NULL;
    ptr = TtaGetEnvString (DAV_URLS);
    if (ptr && (*ptr))
        sprintf (DAVResources,ptr);
    else
     { 
        DAVResources[0]='\0';

        /* save timeout in thot env */
        TtaSetEnvString (DAV_URLS,DAVResources,TRUE);
        modified = TRUE;
     }

   

    /* *********************** SAVING REGISTRY ***************** */
    if (modified) TtaSaveAppRegistry();

    
#ifdef DEBUG_DAV
    fprintf (stderr,"InitDAV..... WebDAV User's preferences are \n");
    fprintf (stderr,"\tuser url: %s\n\tlock scope: %s\n",DAVUserURL,DAVLockScope); 
    fprintf (stderr,"\tdepth: %s\n\ttimeout: %s\n",DAVDepth,DAVTimeout); 
    fprintf (stderr,"\tAwareness: %s\n",(DAVAwareness)?"yes":"no"); 
    fprintf (stderr,"\tAwareness on exit: %s\n",(DAVAwarenessExit)?"yes":"no"); 
    fprintf (stderr,"\tResources: %s\n",DAVResources); 

    /*HTSetTraceMessageMask("pl");*/
#endif


    /* *********************** SETING FILTERS *************** */
    HTNet_addAfter (FilterFailedDependency_handler,"http://*", NULL, 
                                           HT_FAILED_DEPENDENCY,HT_FILTER_MIDDLE);

    HTNet_addAfter (FilterLocked_handler,"http://*", NULL, 
                                           HT_LOCKED,HT_FILTER_MIDDLE);

    HTNet_addAfter (FilterMultiStatus_handler,"http://*", NULL, 
                                           HT_MULTI_STATUS,HT_FILTER_MIDDLE);


    /* *********************** SETING MENUS ***************** */
    /* set lock indicatior toggle. initial state: FALSE */
    DAVLockIndicatorState = FALSE; 
    DAVSetLockIndicator(CurrentDocument);
    
}


/* ********************************************************************* *
 *                      CLOSE DOCUMENT FUNCTION                          *
 * ********************************************************************* */


/*----------------------------------------------------------------------
   DAVFreeLock - ask to user if he/she wants to free pending locks 
                 when closing the session.   
   
  NEED: deal with last document when exiting the application.
   
        Now, when exiting the application, if the document is locked
        by the user (the lock information must be in the local base),
        this function will ask whether the user wants to unlock it.
        If user agrees, an UNLOCK request will be sent. But, under
        Windows machines, this request will be killed when the application
        exit, and no unlock will be done.
                      
  ----------------------------------------------------------------------*/
void DAVFreeLock (Document docid) 
{
    BOOL ok = NO;
    char *lockinfo;
    char *relURI, *absURI, *ptr;
    char label1[DAV_LINE_MAX], label2[DAV_LINE_MAX];

    if (!DAVLibEnable)
      return;

    lockinfo = relURI = absURI = ptr = NULL;
    
    /* if user doesn't want awareness info, neither
     * awareness info on exit, return
     */ 
    if (!(DAVAwareness && DAVAwarenessExit))
        return;
    
#ifdef DEBUG_DAV
    fprintf (stderr,"Closing document %s\n",DocumentURLs[docid]);
#endif

    /* separing URI into hostname and relative parts */
    ok = separateUri (DocumentURLs[docid], DAVFullHostName, &absURI, &relURI);
    
    if (ok && absURI && relURI) 
     {
        /* if there is a lock info in the local base,
         * user has a lock for this resource.
         */
        lockinfo = DAVFindLockToken (absURI, relURI);
        if (lockinfo && *lockinfo) 
         {
            sprintf (label1,TtaGetMessage(AMAYA,AM_LOCKED),DocumentURLs[docid]);
            ptr = DAVBreakString (label1);
            sprintf (label2,TtaGetMessage(AMAYA,AM_UNLOCK_DOCUMENT));
            
            if (DAVConfirmDialog (docid,label1,(ptr)?ptr:" ", label2)) 
             {
                AHTDAVContext *new_davctx = GetUnlockInfo (docid);
                if (new_davctx) 
                 {
                    new_davctx->showIt = NO;    
                    DoUnlockRequest (docid, new_davctx);                    
                 }    
             }
         } /* lockinfo */
     }
}



/* ********************************************************************* *
 *                           REGISTRY OPERATION                          *
 * ********************************************************************* */


/*----------------------------------------------------------------------
   DAVSaveRegistry - save DAV information in the registry

  ----------------------------------------------------------------------*/
void DAVSaveRegistry (void)
{
  if (!DAVLibEnable)
    return;

    /***** DAVUserURL, DAVLockScope, DAVDepth, DAVTimeout *****/
    TtaSetEnvString (DAV_USER_URL,DAVUserURL,TRUE);
    TtaSetEnvString (DAV_LOCK_SCOPE,DAVLockScope,TRUE);
    TtaSetEnvString (DAV_DEPTH,DAVDepth,TRUE);
    TtaSetEnvString (DAV_TIMEOUT,DAVTimeout,TRUE);
    
    /************* DAVAwareness, DAVAwarenessOnExit ************ */
    if (DAVAwareness == YES) 
        TtaSetEnvString (DAV_AWARENESS,"yes",TRUE);
    else 
        TtaSetEnvString (DAV_AWARENESS,"no",TRUE);
    
    if (DAVAwarenessExit == YES)
        TtaSetEnvString (DAV_AWARENESS_EXIT,"yes",TRUE);
    else
        TtaSetEnvString (DAV_AWARENESS_EXIT,"no",TRUE);
    
    
    /************************** DAVResources ******************** */
    TtaSetEnvString (DAV_URLS,DAVResources,TRUE);


    /* *********************** SAVING REGISTRY ***************** */
    TtaSaveAppRegistry();

    
#ifdef DEBUG_DAV
    fprintf (stderr,"DAVSaveRegistry..... WebDAV User's preferences are \n");
    fprintf (stderr,"\tuser url: %s\n\tlock scope: %s\n",DAVUserURL,DAVLockScope); 
    fprintf (stderr,"\tdepth: %s\n\ttimeout: %s\n",DAVDepth,DAVTimeout); 
    fprintf (stderr,"\tAwareness: %s\n",(DAVAwareness)?"yes":"no"); 
    fprintf (stderr,"\tAwareness on exit: %s\n",(DAVAwarenessExit)?"yes":"no"); 
    fprintf (stderr,"\tResources: %s\n",DAVResources); 
#endif

}



/* ********************************************************************* *
 *                               MENU ACTIONS                            *
 * ********************************************************************* */


/*----------------------------------------------------------------------
   DAVLockDocument - Lock the document URL 

  ----------------------------------------------------------------------*/
void DAVLockDocument (Document document, View view)
{
    AHTDAVContext *davctx = NULL;

    if (!DAVLibEnable)
      return;

#ifdef DEBUG_DAV    
    fprintf (stderr,"DAVLockDocument..... Locking document %s\n",DocumentURLs[document]);
    fprintf (stderr,"DAVLockDocument..... creating the dav context object\n");
#endif
    
    /* getting DAV context object */ 
    davctx = GetLockInfo (document);
    if (!davctx) 
     {            
        DAVDisplayMessage (TtaGetMessage (AMAYA, AM_DAV_UNSUPPORTED_PROTOCOL), 
                           DocumentURLs[document]);
     }
    else 
     {
#ifdef DEBUG_DAV
        char *url = DocumentURLs[document];
        fprintf (stderr,"\tabsolute: %s\n\trelative: %s\n",davctx->absoluteURI,davctx->relativeURI);
        fprintf (stderr,"\tdepth: %s\n",HTDAV_DepthHeader(davctx->davheaders));
        fprintf (stderr,"\ttimeout: %s\n",HTDAV_TimeoutHeader(davctx->davheaders));
        fprintf (stderr,"\turl: %s\n",url);
        fprintf (stderr,"\tLock XML body: %s\n",(davctx->xmlbody)?"YES":"NO");
#endif 

        /* executing the request */
        if (!DoLockRequest (document,davctx)) 
            DAVDisplayMessage (TtaGetMessage (AMAYA, AM_LOCK_FAILED), NULL);

     }
        
}



/*----------------------------------------------------------------------
   DAVUlnlocDocument - Unlock document URL

  ----------------------------------------------------------------------*/
void DAVUnlockDocument (Document document, View view) 
{
    AHTDAVContext *davctx = NULL;

    if (!DAVLibEnable)
      return;
    
#ifdef DEBUG_DAV    
    fprintf (stderr,"DAVUnlockDocument..... Unlocking document %s\n",DocumentURLs[document]);
    fprintf (stderr,"DAVUnlockDocument..... creating the dav context object\n");
#endif
  
    davctx = GetUnlockInfo(document);
    if (davctx) 
     {
#ifdef DEBUG_DAV
        fprintf (stderr,"DAVUnlockDocument..... DAV context object:\n");
        fprintf (stderr,"\tabsolute: %s\n\trelative: %s\n",davctx->absoluteURI,davctx->relativeURI);
        fprintf (stderr,"\tdepth: %s\n",HTDAV_DepthHeader(davctx->davheaders));
        fprintf (stderr,"\tlock-token: %s\n",HTDAV_LockTokenHeader(davctx->davheaders));
#endif 
        
        /* do the request */       
        if (!DoUnlockRequest (document,davctx)) 
            DAVDisplayMessage (TtaGetMessage (AMAYA, AM_UNLOCK_FAILED), NULL);
        
        
     }
    else 
     {
        /* *** Should we give to the user the option to unlock a document anyway? YES *** */
        ForceUnlockRequest (document);
     }
}



/*----------------------------------------------------------------------
   DAVProfindDocument - do a Propfind request in the document URL 
   
  ----------------------------------------------------------------------*/
void DAVProfindDocument (Document document, View view) 
{
    AHTDAVContext *davctx= NULL;

    if (!DAVLibEnable)
      return;

#ifdef DEBUG_DAV
    fprintf (stderr,"DAVPropfindDocument.... Profind document %s\n",DocumentURLs[document]);
    fprintf (stderr,"DAVPropfindDocument..... creating the dav context object\n");    
#endif    
    
    davctx = GetPropfindInfo(document);
    if (davctx) 
     {
#ifdef DEBUG_DAV
        fprintf (stderr,"DAVPropfindDocument..... DAV context object:\n");
        fprintf (stderr,"\tabsolute: %s\n\trelative: %s\n",davctx->absoluteURI,davctx->relativeURI);
        fprintf (stderr,"\tdepth: %s\n",HTDAV_DepthHeader(davctx->davheaders));
        fprintf (stderr,"\txml body: %s\n",(davctx->xmlbody));    
#endif
        
        /* YES, show the results*/
        davctx->showIt = YES;

        if (!DoPropfindRequest (document,davctx,FilterPropfind_handler,NULL)) 
            DAVDisplayMessage (TtaGetMessage (AMAYA,AM_PROPFIND_FAILED), NULL);
                
     }
    else 
     {
#ifndef _WINDOWS            
        DAVDisplayMessage (TtaGetMessage (AMAYA, AM_DAV_UNSUPPORTED_PROTOCOL), 
                           DocumentURLs[document]);                        
#endif
        DAVLockIndicatorState = FALSE;
     }   

}



/*----------------------------------------------------------------------
   DAVCopyLockInfo - do a Propfind request in the document URL 
   to discover and copy (to the local base) the lock information
  ----------------------------------------------------------------------*/
void DAVCopyLockInfo (Document document, View view) 
{
    AHTDAVContext *davctx= NULL;
    BOOL ok = NO;

    if (!DAVLibEnable)
      return;

#ifdef DEBUG_DAV
    fprintf (stderr,"DAVCopyLockInfo.... Profind document %s\n",DocumentURLs[document]);
    fprintf (stderr,"DAVCopyLockInfo..... creating the dav context object\n");    
#endif    
    
    davctx = GetPropfindInfo(document);
    if (davctx) 
     {
#ifdef DEBUG_DAV
        fprintf (stderr,"DAVPropfindDocument..... DAV context object:\n");
        fprintf (stderr,"\tabsolute: %s\n\trelative: %s\n",davctx->absoluteURI,davctx->relativeURI);
        fprintf (stderr,"\tdepth: %s\n",HTDAV_DepthHeader(davctx->davheaders));
        fprintf (stderr,"\txml body: %s\n",(davctx->xmlbody));    
#endif
        
        /* YES, show the results*/
        davctx->showIt = YES;

        if (createPropfindBody (YES,davctx->xmlbody,DAV_XML_LEN)) 
            ok = DoPropfindRequest (document,davctx,FilterCopyLockInfo_handler,NULL);
        
        
        if (!ok)
            DAVDisplayMessage (TtaGetMessage (AMAYA,AM_PROPFIND_FAILED), NULL);
        
     }
    else
     {
#ifndef _WINDOWS            
        DAVDisplayMessage (TtaGetMessage (AMAYA, AM_DAV_UNSUPPORTED_PROTOCOL), 
                           DocumentURLs[document]);                        
#endif
        DAVLockIndicatorState = FALSE;
     }        
}



/*----------------------------------------------------------------------
   DAVLockIndicator: Manipulates Lock indicator
  ----------------------------------------------------------------------*/
void DAVLockIndicator (Document document, View view) 
{
        
    /* if lock indicator is TRUE, unlock the document
     * if it's FALSE, lock the document */
    if (DAVLockIndicatorState) 
        DAVUnlockDocument (document,view);    
    else  
        DAVLockDocument (document,view);    

}



/*----------------------------------------------------------------------
   DAVPreferences: shows a dialogue with WebDAV user's preferences
  ----------------------------------------------------------------------*/
void DAVPreferences (Document document, View view) 
{
    if (!DAVLibEnable)
      return;

    DAVShowPreferencesDlg (document);
}


