#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "config.h"
#include "adns.h"

/* declarations related to option processing */

enum ttlmode { tm_none, tm_rel, tm_abs };
enum outputformat { fmt_default, fmt_simple, fmt_inline, fmt_asynch };

struct perqueryflags_remember {
  int show_owner, show_type, show_cname;
  int ttl;
};

extern int ov_env, ov_pipe, ov_asynch;
extern int ov_verbose;
extern adns_rrtype ov_type;
extern int ov_search, ov_qc_query, ov_qc_anshost, ov_qc_cname;
extern int ov_tcp, ov_cname, ov_format;
extern char *ov_id;
extern struct perqueryflags_remember ov_pqfr;

/* declarations related to query processing */

struct query_node {
  struct query_node *next, *back;
  struct perqueryflags_remember pqfr;
  char *id, *owner;
  adns_query qu;
};

extern adns_state ads;
extern struct outstanding_list { struct query_node *head, *tail; } outstanding;

void ensure_adns_init(void);
int query_do(const char *domain);
int query_done(struct query_node *qun, adns_answer *answer, char *result);

/* declarations related to main program and useful utility functions */

void sysfail(const char *what, int errnoval);
void outerr(void);

void *xmalloc(size_t sz);
char *xstrsave(const char *str);

extern int rcode;
extern const char *config_text; /* 0 => use defaults */

#define ADNS_VERSION_STRING "1.0"

#define VERSION_MESSAGE(program) \
 program " (GNU adns) " ADNS_VERSION_STRING "\n\n" COPYRIGHT_MESSAGE

#define VERSION_PRINT_QUIT(program)                               \
  if (fputs(VERSION_MESSAGE(program),stdout) == EOF ||            \
      fclose(stdout)) {                                           \
    perror(program ": write version message");                    \
    quitnow(-1);                                                  \
  }                                                               \
  quitnow(0);

void quitnow(int rc);

#define LIST_INIT(list) ((list).head= (list).tail= 0)
#define LINK_INIT(link) ((link).next= (link).back= 0)

#define LIST_UNLINK_PART(list,node,part) \
  do { \
    if ((node)->part back) (node)->part back->part next= (node)->part next; \
      else                                  (list).head= (node)->part next; \
    if ((node)->part next) (node)->part next->part back= (node)->part back; \
      else                                  (list).tail= (node)->part back; \
  } while(0)

#define LIST_LINK_TAIL_PART(list,node,part) \
  do { \
    (node)->part next= 0; \
    (node)->part back= (list).tail; \
    if ((list).tail) (list).tail->part next= (node); else (list).head= (node); \
    (list).tail= (node); \
  } while(0)

#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
#define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,)

