text: /*-
   * Copyright (c) 2010 Alistair Crooks <agc@NetBSD.org>
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/socket.h>
  
  #include <netinet/in.h>
  
  #include <errno.h>
  #include <inttypes.h>
  #include <netdb.h>
  #include <netpgp.h>
  #include <regex.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  
  #include "hkpc.h"
  
  /* get a socket and connect it to the server */
  int
  hkpc_connect(const char *hostname, const int port, const int fam)
  {
          struct addrinfo  hints;
          struct addrinfo *res;
          char             portstr[32];
  	int		 sock;
          int              rc = 0;
  
          (void) memset(&hints, 0, sizeof(hints));
          hints.ai_family = (fam == 4) ? PF_INET : PF_INET6;
          hints.ai_socktype = SOCK_STREAM;
          (void) snprintf(portstr, sizeof(portstr), "%d", port);
          if ((rc = getaddrinfo(hostname, portstr, &hints, &res)) != 0) {
                  hints.ai_flags = 0;
                  if ((rc = getaddrinfo(hostname, "hkp", &hints, &res)) != 0) {
                          (void) fprintf(stderr, "getaddrinfo: %s",
  					gai_strerror(rc));
                          return -1;
                  }
          }
  	if ((sock = socket((fam == 4) ? AF_INET : AF_INET6, SOCK_STREAM, 0)) < 0) {
                  (void) fprintf(stderr, "socket failed %d\n", errno);
                  freeaddrinfo(res);
                  return -1;
  	}
          if ((rc = connect(sock, res->ai_addr, res->ai_addrlen)) < 0) {
                  (void) fprintf(stderr, "connect failed %d\n", errno);
                  freeaddrinfo(res);
                  return -1;
          }
          freeaddrinfo(res);
          if (rc < 0) {
                  (void) fprintf(stderr, "connect() to %s:%d failed (rc %d)\n",
  				hostname, port, rc);
          }
          return sock;
  }
  
  #define MB(x)	((x) * 1024 * 1024)
  
  /* get required info from the server */
  int
  hkpc_get(char **info, const char *server, const int port, const int family, const char *type, const char *userid)
  {
  	char	buf[MB(1)];
  	int	sock;
  	int	cc;
  	int	rc;
  
  	if ((sock = hkpc_connect(server, port, family)) < 0) {
  		(void) fprintf(stderr, "hkpc_get: can't connect to server '%s'\n", server);
  		return -1;
  	}
  	cc = snprintf(buf, sizeof(buf), "GET /pks/lookup?op=%s&search=%s&options=json", type, userid);
  	if (write(sock, buf, cc) != cc) {
  		(void) fprintf(stderr, "hkpc_get: short write\n");
  		return -1;
  	}
  	for (cc = 0 ; (rc = read(sock, &buf[cc], sizeof(buf) - cc)) > 0 ; cc += rc) {
  	}
  	*info = calloc(1, cc + 1);
  	(void) memcpy(*info, buf, cc);
  	(*info)[cc] = 0x0;
  	(void) close(sock);
  	return cc;
  }
  
  /* jump over http header, then pass the json to the key-formatting function */
  int
  hkpc_print_key(FILE *fp, const char *op, const char *res)
  {
  	static regex_t	text;
  	static int	compiled;
  	regmatch_t	matches[10];
  	int	 	ret;
  
  	if (!compiled) {
  		compiled = 1;
  		(void) regcomp(&text, "\r\n\r\n", REG_EXTENDED);
  	}
  	if (regexec(&text, res, 10, matches, 0) != 0) {
  		return 0;
  	}
  	if (strcmp(op, "index") == 0 || strcmp(op, "vindex") == 0) {
  		ret = netpgp_format_json(fp, &res[(int)matches[0].rm_eo], 1);
  	} else {
  		(void) fprintf(fp, "%s\n", &res[(int)matches[0].rm_eo]);
  		ret = 1;
  	}
  	return ret;
  }
  