Logo Search packages:      
Sourcecode: nd version File versions  Download package

main.c

/*
 * main.c - a terminal interface of nd.
 *
 * Copyright (c) 2002 Yuuichi Teranishi <teranisi@gohome.org>
 * For license terms, see the file COPYING in this directory.
 *
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include "nd.h"
#include <stdarg.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif /* HAVE_STRING_H */
#include <libxml/parser.h>
#include <libxml/nanohttp.h>

#include <errno.h>

int  Optind = 1;
char *Optarg = NULL;
int format = ND_PRINT_AS_HEADER;
int debug = 0;

void
error_exit (int format, const char *fmt, ...)
{
  va_list ap;

  va_start(ap, fmt);
  if (fmt != NULL)
    {
      if (format == ND_PRINT_AS_SEXP)
      {
        fprintf (stdout, "(error \"");
        vfprintf(stdout, fmt, ap);
        fprintf (stdout, "\")\n");
      }
      else
      {
        fprintf (stderr, "Error: ");
        vfprintf (stderr, fmt, ap);
        fprintf (stderr, "\n");
      }
    }
  va_end(ap);
  exit(1);
}

int
Getopt (argc, argv, fmt)
     int argc;
     char **argv;
     const char *fmt;
{
  char *p, *q, c;
  Optarg = NULL;
  if (Optind >= argc)
    return -1;
  p = argv[Optind];

  if (*p++ != '-')
    return -1;
  c = *p;
  if (c == '\0')
    return -1;
  if (*(p + 1) != '\0')
    {
      fprintf (stderr, "unknown long option '-%s'.\n", p);
      exit (1);
    }
  if ((q = strchr (fmt, c)) == NULL)
    {
      fprintf (stderr, "unknown option '-%c'.\n", c);
      exit (1);
    }
  if (++q != NULL && *q == ':')
    {
      if (++Optind >= argc)
      {
        fprintf (stderr, "no parameter for '-%c'.\n", c);
        exit (1);
      }
      Optarg = argv[Optind];
    }
  Optind++;
  return c;
}

#define ND_USAGE "%s version %s\n\
usage: %s [options] url\n\
    if no option, GET url.\n\
    -c dest_url\n\
       COPY url to the dest_url. (Not implemented yet)\n\
    -v\n\
       View property information of url by PROPFIND.\n\
       With -g option, only the specified property is displayed.\n\
    -p file\n\
       Write file content to the url by PUT.\n\
       Use lock token if -t is specified. \n\
    -g name\n\
       Specify the property name for -v option.\n\
    -e name=value\n\
       Edit the property.\n\
       The property named 'name' is changed to 'value'.\n\
       If multiple '-e' options are specified, only the first one takes\n\
       effect.\n\
       -N is required if namespace of the property is other than 'DAV:'\n\
    -N namespace-url\n\
       Specify the property namespace URL for -e or -g option.\n\
    -P file\n\
       POST file content to the url. -T is required.\n\
    -T content_type\n\
       Use content_type as a Content-Type of the POST request.\n\
       Default is `application/x-www-form-urlencoded'.\n\
    -d\n\
       DELETE url. Use lock token if -t is specified. \n\
    -l\n\
       LOCK url.\n\
    -k\n\
       MKCOL url.\n\
    -m dest_url\n\
       MOVE url to the dest_url. (Not implemented yet)\n\
    -o owner\n\
       Specify lock owner. Default is USER environment variable.\n\
    -r\n\
       Execute operation by setting depth as infinity. (Not implemented yet)\n\
    -a realm\n\
       Specify authentication realm for the request.\n\
    -A realm\n\
       Specify proxy authentication realm for the request.\n\
    -s scope\n\
       Specify lock scope (`exclusive' or `shared'). Default is `exclusive'.\n\
    -i timeout\n\
       Specify lock timeout interval. Default is `Infinite'.\n\
    -u\n\
       UNLOCK url. -t option is required.\n\
    -t token\n\
       Use lock token `token'.\n\
    -S\n\
       Print output by s-expression.\n\
    -D\n\
       Debug mode.\n"

void
usage (prog)
     char *prog;
{
  fprintf (stderr, ND_USAGE, PACKAGE, VERSION, prog);
}

void
auth_notify (ctxt)
     void *ctxt;
{
  if (format == ND_PRINT_AS_SEXP)
    {
      int code = xmlNanoHTTPReturnCode(ctxt);
      if (code < 0 || 300 < code)
      {}
      else
      {
        fprintf (stdout, "OK\n");
      }
    }
}

int
authenticate (param, is_proxy)
     ndAuthParamPtr param;
     int is_proxy;
{
  char user[ND_HEADER_LINE_MAX];
  char *realm = ndAuthParamValue (param, "realm");

  if (realm)
    {
      fprintf (stderr, "%sUsername for %s: ",
             is_proxy? "Proxy " : "",
             realm);
      if (fgets (user, ND_HEADER_LINE_MAX, stdin) == NULL)
      return -1;
      if (user [ strlen (user) - 1 ] == '\n')
      user [ strlen (user) - 1 ] = '\0';
      ndAuthParamSetValue (param, "user", user);
      ndAuthParamSetValue (param, "password",
                     getpass (is_proxy?
                            "Proxy Password: " : "Password: "));
      return 0;
    }
  return -1;
}

#undef WAIT_FOR_END

void
null_error_handler (void *ctx, const char *msg, ...)
{}

int
main (argc, argv)
     int argc;
     char** argv;
{
  int optc;
  int mode = 'g';
  char *url;
  char *token = NULL;
  char *timeout = NULL;
  char *infile = NULL;
  char *owner = NULL;
  char *dest_url = NULL;
  char *content_type = "application/x-www-form-urlencoded";
  char *auth_realm  = NULL;
  char *pauth_realm = NULL;
  char *edit = NULL;
  char *prop = NULL;
  char *ns = NULL;
  int scope;
  int infinite = 0;
  int force_overwrite = 0;
  ndAuthCtxtPtr auth;

  /* OMIT xml errors. */
  xmlSetGenericErrorFunc (NULL, null_error_handler);

  while ((optc = Getopt (argc, argv, "c:de:fg:i:lm:o:vukrs:t:p:a:A:ST:P:DN:"))
       != -1)
    {
      switch (optc)
      {
      case 'c':
        mode = 'c';
        dest_url = Optarg;
        break;
      case 'm':
        mode = 'm';
        dest_url = Optarg;
        break;
      case 'e':
        mode = 'e';
        edit = Optarg;
        break;
      case 'g':
        prop = Optarg;
        break;
      case 'l':
        mode = 'l';
        timeout = "Infinite";
        scope = ND_LOCK_SCOPE_EXCLUSIVE;
        break;
      case 'i':
        timeout = Optarg;
        break;
      case 'o':
        owner = Optarg;
        break;
      case 'v':
        mode = 'v';
        break;
      case 'd':
        mode = 'd';
        break;
      case 'D':
        debug = 1;
        break;
      case 'f':
        force_overwrite = 1;
        break;
      case 'S':
        format = ND_PRINT_AS_SEXP;
        break;
      case 'a':
        auth_realm = Optarg;
        break;
      case 'A':
        pauth_realm = Optarg;
        break;
      case 'P':
        mode = 'P';
        infile = Optarg;
        break;
      case 'T':
        content_type = Optarg;
        break;
      case 'N':
        ns = Optarg;
        break;
      case 'u':
        mode = 'u';
        break;
      case 'k':
        mode = 'k';
        break;
      case 'r':
        infinite = 1;
        break;
      case 's':
        if (!strcmp ("shared", Optarg))
          scope = ND_LOCK_SCOPE_SHARED;
        break;
      case 't':
        token = Optarg;
        break;
      case 'p':
        mode = 'p';
        infile = Optarg;
        break;
      default:
        usage (argv[0]);
        exit (1);
      }
    }
  url = argv[Optind];
  if (url == NULL)
    {
      usage (argv[0]);
      exit (1);
    }
  auth = ndCreateAuthCtxt (authenticate, auth_notify,
                     auth_realm, pauth_realm);
  switch (mode)
    {
    case 'c':
      {
      int code;
      code = ndCopy (url, auth, dest_url, force_overwrite, token);
      ndFreeAuthCtxt (auth);
      if (code < 0 || 300 < code)
        {
          error_exit (format, "COPY failed, `%s'", ndReasonPhrase (code));
        }
      break;
      }
    case 'e':
      {
      int code;
      ndNodeInfoPtr ret = NULL;
      char *name = edit;
      char *value = NULL;
      for (value = name; *value != '\0' && *value != '=' ; value++);
      if (value != '\0')
        {
          *value = '\0';
          value++;
        }
      if (*value == '\0')
        {
          value = NULL;
        }
      code = ndPropPatch (url, auth, name, value, ns, token, &ret);
      if (code < 0 || 300 < code)
        {
          error_exit (format, "PROPPATCH failed, `%s'",
                  ndReasonPhrase (code));
        }
      else if (code == 207)
        {
          ndNodeInfoListPrint (stdout, ret, format);
        }
      break;
      }
    case 'm':
      {
      int code;
      code = ndMove (url, auth, dest_url, force_overwrite, token);
      ndFreeAuthCtxt (auth);
      if (code < 0 || 300 < code)
        {
          error_exit (format, "MOVE failed, `%s'", ndReasonPhrase (code));
        }
      break;
      }
    case 'g':
      {
#ifndef WAIT_FOR_END
      char *ct_return = NULL;
      int  code;
      if (token != NULL)
        {
          error_exit (format, "token is not required");
        }
      code = ndGetPrint (url, auth, &ct_return, stdout);
      ndFreeAuthCtxt (auth);
      if (code < 0 || 300 < code)
        {
          error_exit (format, "GET failed, `%s'", ndReasonPhrase (code));
        }
#else
      xmlBufferPtr buf = NULL;
      int code;
      char *ct_return = NULL;

      if (token != NULL)
        {
          error_exit (format, "token is not required");
        }
      code = ndGet (url, auth, &ct_return, &buf);
      ndFreeAuthCtxt (auth);
      if (code < 0 || 300 < code)
        {
          error_exit (format, "GET failed, `%s'", ndReasonPhrase (code));
        }
      if (buf)  fprintf (stdout, "%s", xmlBufferContent(buf));
#endif
      }
      break;
    case 'v':
      {
      ndNodeInfoPtr ret = NULL;
      int code;
      int depth;

      if (token != NULL)
        {
          error_exit (format, "token is not required");
        }
      if (url[strlen(url) - 1] == '/')
        {
          if (infinite)
            depth = ND_DEPTH_INFINITE;
          else
            depth = ND_DEPTH_1;
        }
      else
        depth = ND_DEPTH_0;
      code = ndPropFind (url, auth, prop, ns, depth, &ret);
      ndFreeAuthCtxt (auth);
      if (ret)
        {
          ndNodeInfoListPrint (stdout, ret, format);
        }
      else
        {
          error_exit (format, "PROPFIND failed, `%s'",
                  ndReasonPhrase (code));
        }
      }
      break;
    case 'l':
      {
      ndLockInfoPtr lock = NULL;
      int code;
      int depth;

      if (url[strlen(url) - 1] == '/')
        {
          if (infinite)
            depth = ND_DEPTH_INFINITE;
          else
            depth = ND_DEPTH_1;
        }
      else
        depth = ND_DEPTH_0;
      code = ndLock (url, auth, depth,
                   owner ? owner : getenv ("USER"),
                   scope, timeout, &lock);
      ndFreeAuthCtxt (auth);
      if (lock)
        {
          ndLockInfoPrint (stdout, lock, format);
          fprintf (stdout, "\n");
        }
      else
        {
          error_exit (format, "LOCK failed, `%s'", ndReasonPhrase (code));
        }
      }
      break;
    case 'u':
      {
      int ret;
      int depth;

      if (token == NULL)
        {
          error_exit (format, "token is required");
        }
      if (url[strlen(url) - 1] == '/')
        {
          if (infinite)
            depth = ND_DEPTH_INFINITE;
          else
            depth = ND_DEPTH_0;
        }
      else
        depth = ND_DEPTH_0;
      ret = ndUnlock (url, auth, depth, token);
      ndFreeAuthCtxt (auth);
      if (ret < 0 || 300 < ret)
        {
          error_exit (format, "UNLOCK failed, `%s'", ndReasonPhrase (ret));
          exit (1);
        }
      }
      break;
    case 'P':
      {
      xmlBufferPtr buf = xmlBufferCreate ();
      int len;
      unsigned char s [1024];
      int ret;
      FILE *fp;
      if ((fp = fopen (infile, "r")) == NULL)
        error_exit (format, "%s, %s", infile, strerror (errno));
      while ((len = fread (s, sizeof(unsigned char), sizeof (s), fp)) > 0)
        xmlBufferAdd (buf, s, len);
      fclose (fp);
      ret = ndPostPrint (url, auth,
                     (char *) xmlBufferContent (buf),
                     xmlBufferLength (buf), &content_type, stdout);
      ndFreeAuthCtxt (auth);
      if (ret < 0 || 300 < ret)
        error_exit (format, "POST failed, `%s'", ndReasonPhrase (ret));
      break;
      }
    case 'k':
      {
      int ret;
      ret = ndMkCol (url, auth, token);
      ndFreeAuthCtxt (auth);
      if (ret < 0 || 300 < ret)
        {
          error_exit (format, "MKCOL failed, `%s'", ndReasonPhrase (ret));
        }
      }
      break;
    case 'd':
      {
      int ret;
      ret = ndDelete (url, auth, token);
      ndFreeAuthCtxt (auth);
      if (ret < 0 || 300 < ret)
        {
          error_exit (format, "DELETE failed, `%s'", ndReasonPhrase (ret));
        }
      break;
      }
    case 'p':
      {
      xmlBufferPtr buf = xmlBufferCreate ();
      int len;
      unsigned char s [1024];
      int code;
      FILE *fp;
      ndNodeInfoPtr ret = NULL;

      if ((fp = fopen (infile, "r")) == NULL)
        {
          error_exit (format, "%s, %s", infile, strerror (errno));
        }
      while ((len = fread (s, sizeof(unsigned char), sizeof (s), fp)) > 0)
        {
          xmlBufferAdd (buf, s, len);
        }
      fclose (fp);
      code = ndPut (url, auth,
                 (char *) xmlBufferContent (buf),
                  xmlBufferLength (buf), token, &ret);
      ndFreeAuthCtxt (auth);
      if (code < 0 || 300 < code)
        {
          error_exit (format, "PUT failed, `%s'", ndReasonPhrase (code));
        }
      else
        {
          ndNodeInfoListPrint (stdout, ret, format);
        }
      break;
      }
    }
  exit (0);
}

Generated by  Doxygen 1.6.0   Back to index