Added reset command.
[doldaconnect.git] / lib / uilib.c
index 034c823..031fc16 100644 (file)
@@ -96,8 +96,12 @@ static int state = -1;
 static int fd = -1;
 static iconv_t ichandle;
 static int resetreader = 1;
-static char *dchostname = NULL;
 static struct addrinfo *hostlist = NULL, *curhost = NULL;
+struct {
+    char *hostname;
+    int family;
+    int sentcreds;
+} servinfo;
 
 static struct dc_response *makeresp(void)
 {
@@ -276,9 +280,9 @@ void dc_disconnect(void)
     while((resp = dc_getresp()) != NULL)
        dc_freeresp(resp);
     dc_uimisc_disconnected();
-    if(dchostname != NULL)
-       free(dchostname);
-    dchostname = NULL;
+    if(servinfo.hostname != NULL)
+       free(servinfo.hostname);
+    memset(&servinfo, 0, sizeof(servinfo));
 }
 
 void dc_freeresp(struct dc_response *resp)
@@ -374,7 +378,7 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...)
     struct qcmd *qcmd;
     int num, freepart;
     va_list al;
-    char *final;
+    char *final, *sarg;
     wchar_t **toks;
     wchar_t *buf;
     wchar_t *part, *tpart;
@@ -386,7 +390,7 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...)
     va_start(al, data);
     while((part = va_arg(al, wchar_t *)) != NULL)
     {
-       if(!wcscmp(part, L"%%a"))
+       if(!wcscmp(part, L"%a"))
        {
            for(toks = va_arg(al, wchar_t **); *toks != NULL; toks++)
            {
@@ -406,25 +410,36 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...)
        } else {
            if(*part == L'%')
            {
-               /* This demands that all arguments that are passed to the
-                * function are of equal length, that of an int. I know
-                * that GCC does that on IA32 platforms, but I do not know
-                * which other platforms and compilers that it applies
-                * to. If this breaks your platform, please mail me about
-                * it.
-                */
-               part = vswprintf2(tpart = (part + 1), al);
-               for(; *tpart != L'\0'; tpart++)
+               tpart = part + 1;
+               if(!wcscmp(tpart, L"i"))
                {
-                   if(*tpart == L'%')
+                   freepart = 1;
+                   part = swprintf2(L"%i", va_arg(al, int));
+               } else if(!wcscmp(tpart, L"s")) {
+                   freepart = 1;
+                   part = icmbstowcs(sarg = va_arg(al, char *), NULL);
+                   if(part == NULL)
                    {
-                       if(tpart[1] == L'%')
-                           tpart++;
-                       else
-                           va_arg(al, int);
+                       if(buf != NULL)
+                           free(buf);
+                       return(-1);
                    }
+               } else if(!wcscmp(tpart, L"ls")) {
+                   part = va_arg(al, wchar_t *);
+               } else if(!wcscmp(tpart, L"ll")) {
+                   freepart = 1;
+                   part = swprintf2(L"%lli", va_arg(al, long long));
+               } else if(!wcscmp(tpart, L"f")) {
+                   freepart = 1;
+                   part = swprintf2(L"%f", va_arg(al, double));
+               } else if(!wcscmp(tpart, L"x")) {
+                   freepart = 1;
+                   part = swprintf2(L"%x", va_arg(al, int));
+               } else {
+                   if(buf != NULL)
+                       free(buf);
+                   return(-1);
                }
-               freepart = 1;
            } else {
                freepart = 0;
            }
@@ -532,7 +547,8 @@ int dc_handleread(void)
            }
        }
        if(curhost->ai_canonname != NULL)
-           dchostname = sstrdup(curhost->ai_canonname);
+           servinfo.hostname = sstrdup(curhost->ai_canonname);
+       servinfo.family = curhost->ai_family;
        state = 1;
        resetreader = 1;
        break;
@@ -744,17 +760,48 @@ int dc_handleread(void)
     return(0);
 }
 
+static void mkcreds(struct msghdr *msg)
+{
+    struct ucred *ucred;
+    static char buf[CMSG_SPACE(sizeof(*ucred))];
+    struct cmsghdr *cmsg;
+    
+    msg->msg_control = buf;
+    msg->msg_controllen = sizeof(buf);
+    cmsg = CMSG_FIRSTHDR(msg);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_CREDENTIALS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(*ucred));
+    ucred = (struct ucred *)CMSG_DATA(cmsg);
+    ucred->pid = getpid();
+    ucred->uid = getuid();
+    ucred->gid = getgid();
+    msg->msg_controllen = cmsg->cmsg_len;
+}
+
 int dc_handlewrite(void)
 {
     int ret;
     int errnobak;
+    struct msghdr msg;
+    struct iovec bufvec;
     
     switch(state)
     {
     case 1:
        if(queue->buflen > 0)
        {
-           ret = send(fd, queue->buf, queue->buflen, MSG_NOSIGNAL | MSG_DONTWAIT);
+           memset(&msg, 0, sizeof(msg));
+           msg.msg_iov = &bufvec;
+           msg.msg_iovlen = 1;
+           bufvec.iov_base = queue->buf;
+           bufvec.iov_len = queue->buflen;
+           if((servinfo.family == PF_UNIX) && !servinfo.sentcreds)
+           {
+               mkcreds(&msg);
+               servinfo.sentcreds = 1;
+           }
+           ret = sendmsg(fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT);
            if(ret < 0)
            {
                if((errno == EAGAIN) || (errno == EINTR))
@@ -1108,7 +1155,8 @@ int dc_connect(char *host)
            fd = -1;
        } else {
            if(curhost->ai_canonname != NULL)
-               dchostname = sstrdup(curhost->ai_canonname);
+               servinfo.hostname = sstrdup(curhost->ai_canonname);
+           servinfo.family = curhost->ai_family;
            state = 1;
            break;
        }
@@ -1188,7 +1236,25 @@ void dc_freeires(struct dc_intresp *ires)
     free(ires);
 }
 
+int dc_checkprotocol(struct dc_response *resp, int revision)
+{
+    struct dc_intresp *ires;
+    int low, high;
+    
+    if(resp->code != 201)
+       return(-1);
+    resp->curline = 0;
+    if((ires = dc_interpret(resp)) == NULL)
+       return(-1);
+    low = ires->argv[0].val.num;
+    high = ires->argv[0].val.num;
+    dc_freeires(ires);
+    if((revision < low) || (revision > high))
+       return(-1);
+    return(0);
+}
+
 const char *dc_gethostname(void)
 {
-    return(dchostname);
+    return(servinfo.hostname);
 }