/*
  Unix domain socket libs
 */

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>

#include "udlib.h"

#define UD_BUFSIZE 1024
struct sockaddr_un usock, csock;
char lbuf[UD_BUFSIZE];

int mkudservd(char *path)
{
  int sockfd = -1;
  sockfd = socket(PF_UNIX, SOCK_DGRAM, 0);
  if (sockfd < 0) return sockfd;
  memset(&usock, 0, sizeof(usock));
  usock.sun_family = AF_UNIX;
  strncpy(usock.sun_path, path, UNIX_PATH_MAX - 1);
  if (bind(sockfd, (struct sockaddr *) &usock, sizeof(usock)) < 0)
    return -1;
  return sockfd;
}

int mkudclid(char *path)
{
  int sockfd = -1;
  int fd;
  char tmppath[] = "/tmp/screen-uim.XXXXXX";
  sockfd = socket(PF_UNIX, SOCK_DGRAM, 0);
  if (sockfd < 0) return sockfd;
  memset(&usock, 0, sizeof(usock));
  memset(&csock, 0, sizeof(csock));
  usock.sun_family = AF_UNIX;
  strncpy(usock.sun_path, path, UNIX_PATH_MAX - 1);
  csock.sun_family = AF_UNIX;
  fd = mkstemp(tmppath);
  if(fd < 0) return -1;
  close(fd);
  unlink(tmppath);
  strncpy(csock.sun_path, tmppath, UNIX_PATH_MAX - 1);
  if (bind(sockfd, (struct sockaddr *) &csock, sizeof(csock)) < 0)
    return -1;
  unlink(tmppath);
  return sockfd;
}

char *udreadline(int sockfd)
{
  char *r, llbuf[UD_BUFSIZE];
  // check local buf
  // - return a line in buf if it existed
  r = udgetline();
  if (r != NULL) return r;

  // read from network
  memset(llbuf, 0, UD_BUFSIZE);
  recvfrom(sockfd, llbuf, UD_BUFSIZE - 1, 0, NULL, 0);

  // store to local buf
  udsetbuf(llbuf);
  // - return a line in buf if it existed
  r = udgetline();
  return r;
}

char *udgetline()
{
  int len;
  char *p, *ret;
  len = strlen(lbuf);
  if (len <= 0) return NULL;
  p = strchr(lbuf, '\n');
  if (p == NULL) return NULL;
  ret = (char *) malloc(p - lbuf + 1);
  strncpy(ret, lbuf, (p - lbuf));
  ret[p - lbuf] = 0;
  memmove(lbuf, lbuf + len + 1, UD_BUFSIZE - len - 1);
  return ret;
}

char *udsetbuf(char *buf)
{
  int l;
  l = strlen(buf);
  if (l > UD_BUFSIZE) l = UD_BUFSIZE;
  memmove(lbuf + l, lbuf, (UD_BUFSIZE - l));
  memcpy(lbuf, buf, l);
  return NULL;
}

void udsendto(int sfd, char *buf)
{
  int l;
  l = strlen(buf);
  sendto(sfd, (void *) buf, l, 0, (struct sockaddr *) &usock, sizeof(usock));
}
