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

libclient.c

/* libclient.c -- shared code for client program to communicate with server
   $Id: libclient.c,v 1.11 2002/04/09 03:36:33 jsh Exp $

   Copyright (C) 1999 John Harper <john@dcs.warwick.ac.uk>

   This file is part of sawmill.

   sawmill is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   sawmill is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with sawmill; see the file COPYING.   If not, write to
   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "sawmill.h"
#include "server.h"
#include "libclient.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

#ifdef HAVE_UNIX
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/un.h>
# include <pwd.h>
# include <netdb.h>

# ifdef HAVE_FCNTL_H
#  include <fcntl.h>
# endif

# ifdef HAVE_UNISTD_H
#  include <unistd.h>
# endif

# ifdef HAVE_SYS_UTSNAME_H
#  include <sys/utsname.h>
# endif

# ifndef PATH_MAX
#  define PATH_MAX 256
# endif
#endif /* HAVE_UNIX */

static void (*close_fun)(void);
static char * (*eval_fun)(char *form, int *lenp, int *errorp);

#define PROTOCOL_X11_VERSION 1



/* copied from src/unix_main.c */
static char *
system_name(void)
{
    u_char buf[256];
    struct hostent *h;

    static char *system_name;
    if(system_name)
      return system_name;

#ifdef HAVE_GETHOSTNAME
    if(gethostname(buf, 256))
      return rep_NULL;
#else
    {
      struct utsname uts;
      uname(&uts);
      strncpy(buf, uts.nodename, 256);
    }
#endif
    h = gethostbyname(buf);
    if(h)
    {
      if(!strchr(h->h_name, '.'))
      {
          /* The official name is not fully qualified. Try looking
             through the list of alternatives. */
          char **aliases = h->h_aliases;
          while(*aliases && !strchr(*aliases, '.'))
            aliases++;
          system_name = strdup(*aliases ? *aliases : h->h_name);
      }
      else
          system_name = strdup((u_char *)h->h_name);
    }
    else
      system_name = strdup(buf);
    return system_name;
}

static char *
canonical_host (char *host)
{
    static char buf[256];
    char *ptr;

    /* check that the name is fully qualified */
    if (!strchr (host, '.'))
    {
      struct hostent *h = gethostbyname (host);
      if (h != 0)
      {
          if (!strchr (h->h_name, '.'))
          {
            char **aliases = h->h_aliases;
            while (*aliases && !strchr (*aliases, '.'))
                aliases++;
            host = *aliases ? *aliases : h->h_name;
          }
          else
            host = h->h_name;
      }
    }

    ptr = buf;
    while (*host != 0)
    {
      *ptr++ = tolower (*host);
      host++;
    }
    return buf;
}

static char *
canonical_display (char *name)
{
    static char buf[256];
    char *ptr = buf;
    if (strncmp ("unix:", name, 5) == 0)
      name += 4;
    if (*name == ':')
    {
      char *host = system_name ();
      if (host != 0)
          strcpy (ptr, host);
      else
          *ptr = 0;
      ptr += strlen (ptr);
    }
    else
    {
      char *fq;
      while (*name && *name != ':')
          *ptr++ = *name++;
      *ptr = 0;
      fq = canonical_host (buf);
      if (fq != buf)
      {
          strcpy (buf, fq);
          ptr = buf + strlen (buf);
      }
    }
    *ptr++ = *name++;
    while (*name && *name != '.')
      *ptr++ = *name++;
    if (*name == 0)
      strcpy (ptr, ".0");
    else
      strcpy (ptr, name);
    return buf;
}

static char *
user_login_name (void)
{
    char *tmp = getlogin ();
    if(tmp == 0)
    {
      struct passwd *pwd = getpwuid(geteuid());
      if (pwd != 0)
          tmp = pwd->pw_name;
    }
    return tmp;
}


/* using the X based server io */

Atom xa_sawfish_request, xa_sawfish_request_win;
Window portal, request_win;
Display *dpy;

static char *
net_server_eval (char *form, int *lenp, int *errorp)
{
    u_char *data = 0;
    u_long nitems;
    XEvent ev;

    XChangeProperty (dpy, portal, xa_sawfish_request, XA_STRING,
                 8, PropModeReplace, form, strlen (form));
    /* swallow the event created by the above */
    XWindowEvent (dpy, portal, PropertyChangeMask, &ev);

    ev.xclient.type = ClientMessage;
    ev.xclient.window = DefaultRootWindow (dpy);
    ev.xclient.message_type = xa_sawfish_request;
    ev.xclient.format = 32;
    ev.xclient.data.l[0] = PROTOCOL_X11_VERSION;
    ev.xclient.data.l[1] = portal;
    ev.xclient.data.l[2] = xa_sawfish_request;
    ev.xclient.data.l[3] = (lenp != 0);
    XSendEvent (dpy, request_win, False, 0L, &ev);

    /* Wait for the wm to delete or update the results */
    XWindowEvent (dpy, portal, PropertyChangeMask, &ev);

    if (lenp != 0)
    {
      Atom type;
      int format;
        long long_length = 16;
      u_long bytes_after;

      while (1)
      {
          if (data != 0)
            XFree (data);
          if (XGetWindowProperty (dpy, portal, xa_sawfish_request, 0,
                            long_length, False, XA_STRING,
                            &type, &format, &nitems,
                            &bytes_after, &data) != Success)
            return 0;
          if (type != XA_STRING || format != 8 )
            return 0;
          if (bytes_after == 0)
            break;
          long_length += (bytes_after / 4) + 1;
      }
      
      if(nitems > 0)
      {
          char *ret = malloc (nitems - 1);
          memcpy (ret, data + 1, nitems - 1);
          *lenp = nitems - 1;
          *errorp = (*data != '\001');
          XFree (data);
          return ret;
      }
    }
    return 0;
}

static void
net_server_close (void)
{
    XDestroyWindow (dpy, portal);
    XCloseDisplay (dpy);
}

/* returns 0 if ok, <0 if error, >0 if server doesn't exist */
static int
net_server_init (char *display)
{
    Atom type;
    int format;
    u_long bytes_after, nitems;
    u_char *data;

    dpy = XOpenDisplay (display);
    if (dpy == 0)
      return 1;

    xa_sawfish_request = XInternAtom (dpy, "_SAWFISH_REQUEST", False);
    xa_sawfish_request_win = XInternAtom (dpy, "_SAWFISH_REQUEST_WIN", False);

    if (XGetWindowProperty (dpy, DefaultRootWindow (dpy),
                      xa_sawfish_request_win, 0, 1, False,
                      XA_CARDINAL, &type, &format, &nitems,
                      &bytes_after, &data) != Success
        || type != XA_CARDINAL || format != 32 || nitems != 1)
    {
      return 1;
    }

    request_win = *(Window *) data;
    portal = XCreateSimpleWindow (dpy, DefaultRootWindow (dpy),
                          -100, -100, 10, 10, 0, 0, 0);
    XSelectInput (dpy, portal, PropertyChangeMask);

    eval_fun = net_server_eval;
    close_fun = net_server_close;

    return 0;
}


/* unix domain socket server */

#ifdef HAVE_UNIX

int socket_fd = -1;

#define SOCK_IO(op, sock, buf, len)             \
      char *buf__ = (char *)buf;                \
      int todo__ = len;                   \
      while(todo__ > 0) {                       \
          int this__ = op (sock, buf__, todo__);      \
          if(this__ < 0) {                      \
            if (errno != EINTR)                 \
                return -1;                      \
          }                               \
          else if(this__ == 0)                  \
            break;                              \
          else {                          \
            todo__ -= this__;             \
            buf__ += this__;              \
          }                               \
      }                                   \
      return len - todo__;

static int
sock_write (int fd, void *buf, size_t len)
{
    SOCK_IO (write, fd, buf, len);
}

static int
sock_read (int fd, void *buf, size_t len)
{
    SOCK_IO (read, fd, buf, len);
}

static char *
unix_server_eval (char *form, int *lenp, int *errorp)
{
    /* Protocol is; >req_eval:1, >FORM-LEN:4, >FORM:?, <RES-LEN:4, <RES:?
       in the local byte-order. */
    u_char req = (lenp != 0) ? req_eval : req_eval_async;
    u_long len = strlen(form);
    char *result;

    if(sock_write(socket_fd, &req, 1) != 1
       || sock_write(socket_fd, &len, sizeof(u_long)) != sizeof(u_long)
       || sock_write(socket_fd, form, len) != len
       || (req != req_eval_async
         && sock_read(socket_fd, &len, sizeof(u_long)) != sizeof(u_long)))
    {
      perror("eval_req");
      return 0;
    }
    if(lenp != 0)
    {
      if(len > 0)
      {
          char state;
          result = malloc (len - 1);
          if(result == 0
             || sock_read(socket_fd, &state, 1) != 1
             || sock_read(socket_fd, result, len - 1) != len - 1)
          {
            perror("eval_req");
            free (result);
            return 0;
          }
          *lenp = len - 1;
          *errorp = (state != '\001');
          return result;
      }
    }
    return 0;
}

static void
unix_server_close (void)
{
    close(socket_fd);
}

/* returns 0 if ok, <0 if error, >0 if server doesn't exist */
static int
unix_server_init (char *display)
{
    struct sockaddr_un addr;
    sprintf(addr.sun_path, SAWMILL_SOCK_DIR "/%s",
          user_login_name (), display);
    addr.sun_family = AF_UNIX;

    socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(socket_fd >= 0)
    {
      if(connect(socket_fd, (struct sockaddr *)&addr,
               sizeof(addr.sun_family) + strlen(addr.sun_path) + 1) == 0)
      {
          eval_fun = unix_server_eval;
          close_fun = unix_server_close;
          return 0;
      }
      close (socket_fd);
      fprintf (stderr, "error: can't connect to socket %s\n", addr.sun_path);
      return 1;
    }
    perror ("socket");
    return -1;
}

#endif /* HAVE_UNIX */


/* entry points */

int
client_open (char *display)
{
    int ret;

    if (display == 0)
      display = getenv ("DISPLAY");
    if (display == 0)
    {
      fprintf (stderr, "no display specified\n");
      return -1;
    }

    display = canonical_display (display);

#ifdef HAVE_UNIX
    ret = unix_server_init (display);
    if (ret > 0)
#endif
      ret = net_server_init (display);
    return ret;
}

char *
client_eval (char *form, int *lenp, int *errorp)
{
    return (*eval_fun) (form, lenp, errorp);
}

void
client_close (void)
{
    (*close_fun) ();
}

Generated by  Doxygen 1.6.0   Back to index