struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
			  const struct cred *cred, key_perm_t perm,
			  unsigned long flags,
			  struct key_restriction *restrict_link,
			  struct key *dest)
{
	struct key *keyring;
	int ret;

	keyring = key_alloc(&key_type_keyring, description,
			    uid, gid, cred, perm, flags, restrict_link);
	if (!IS_ERR(keyring)) {
		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
		if (ret < 0) {
			key_put(keyring);
			keyring = ERR_PTR(ret);
		}
	}

	return keyring;
}


fill_indent(PInfo pi, char *buf, size_t size) {
    size_t	cnt;

    if (0 < (cnt = helper_stack_depth(&pi->helpers))) {
	cnt *= 2;
	if (size < cnt + 1) {
	    cnt = size - 1;
	}
	memset(buf, ' ', cnt);
	buf += cnt;
    }
    *buf = '\0';
}


get_id_from_attrs(PInfo pi, Attr a) {
    for (; 0 != a->name; a++) {
	if ('i' == *a->name && '\0' == *(a->name + 1)) {
	    unsigned long	id = 0;
	    const char		*text = a->value;
	    char		c;

	    for (; '\0' != *text; text++) {
		c = *text;
		if ('0' <= c && c <= '9') {
		    id = id * 10 + (c - '0');
		} else {
		    set_error(&pi->err, "bad number format", pi->str, pi->s);
		    return 0;
		}
	    }
	    return id;
	}
    }
    return 0;
}


aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
			     as_t as)
{
  int i;

  /* If this is first AS set member, create new as-set segment. */
  if (asset == NULL)
    {
      asset = assegment_new (AS_SET, 1);
      if (! aspath->segments)
	aspath->segments = asset;
      else
        {
          struct assegment *seg = aspath->segments;
          while (seg->next)
            seg = seg->next;
          seg->next = asset;
        }
      asset->type = AS_SET;
      asset->length = 1;
      asset->as[0] = as;
    }
  else
    {
      /* Check this AS value already exists or not. */
      for (i = 0; i < asset->length; i++)
	if (asset->as[i] == as)
	  return asset;

      asset->length++;
      asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
                            asset->length * AS_VALUE_SIZE);
      asset->as[asset->length - 1] = as;
    }

  return asset;
}


aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
{
  if (! (aspath1 && aspath2) )
    return 0;

  if ( !(aspath1->segments && aspath2->segments) )
    return 0;

  if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
      || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
    return 0;

  if (aspath1->segments->as[0] == aspath2->segments->as[0])
    return 1;

  return 0;
}


aspath_hash_alloc (void *arg)
{
  const struct aspath *aspath = arg;
  struct aspath *new;

  /* Malformed AS path value. */
  assert (aspath->str);
  if (! aspath->str)
    return NULL;

  /* New aspath structure is needed. */
  new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath));

  /* Reuse segments and string representation */
  new->refcnt = 0;
  new->segments = aspath->segments;
  new->str = aspath->str;
  new->str_len = aspath->str_len;

  return new;
}


aspath_firstas_check (struct aspath *aspath, as_t asno)
{
  if ( (aspath == NULL) || (aspath->segments == NULL) )
    return 0;

  if (aspath->segments
      && (aspath->segments->type == AS_SEQUENCE)
      && (aspath->segments->as[0] == asno ))
    return 1;

  return 0;
}


aspath_print_all_vty (struct vty *vty)
{
  hash_iterate (ashash,
		(void (*) (struct hash_backet *, void *))
		aspath_show_all_iterator,
		vty);
}


aspath_leftmost (struct aspath *aspath)
{
  struct assegment *seg = aspath->segments;
  as_t leftmost = 0;

  if (seg && seg->length && seg->type == AS_SEQUENCE)
    leftmost = seg->as[0];

  return leftmost;
}


aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
{
#define SNMP_PATHSEG_MAX 1024

  if (!snmp_stream)
    snmp_stream = stream_new (SNMP_PATHSEG_MAX);
  else
    stream_reset (snmp_stream);

  if (!as)
    {
      *varlen = 0;
      return NULL;
    }
  aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */

  *varlen = stream_get_endp (snmp_stream);
  return stream_pnt(snmp_stream);
}


aspath_confed_check (struct aspath *aspath)
{
  struct assegment *seg;

  if ( !(aspath && aspath->segments) )
    return 0;

  seg = aspath->segments;

  while (seg)
    {
      if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
	  return 1;
      seg = seg->next;
    }
  return 0;
}


String *Item_func_md5::val_str_ascii(String *str)
{
  DBUG_ASSERT(fixed == 1);
  String * sptr= args[0]->val_str(str);
  str->set_charset(&my_charset_bin);
  if (sptr)
  {
    uchar digest[MD5_HASH_SIZE];

    null_value=0;
    compute_md5_hash((char *) digest, (const char *) sptr->ptr(), sptr->length());
    if (str->alloc(32))				// Ensure that memory is free
    {
      null_value=1;
      return 0;
    }
    array_to_hex((char *) str->ptr(), digest, MD5_HASH_SIZE);
    str->length((uint) 32);
    return str;
  }
  null_value=1;
  return 0;
}


String *Item_func_aes_decrypt::val_str(String *str)
{
  DBUG_ASSERT(fixed == 1);
  char key_buff[80];
  String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
  String *sptr, *key;
  THD *thd= current_thd;
  ulong aes_opmode;
  iv_argument iv_arg;
  DBUG_ENTER("Item_func_aes_decrypt::val_str");

  sptr= args[0]->val_str(str);			// String to decrypt
  key=  args[1]->val_str(&tmp_key_value);	// Key
  aes_opmode= thd->variables.my_aes_mode;
  DBUG_ASSERT(aes_opmode <= MY_AES_END);

  if (sptr && key)  			// Need to have both arguments not NULL
  {
    const unsigned char *iv_str=
      iv_arg.retrieve_iv_ptr((enum my_aes_opmode) aes_opmode, arg_count, args,
      func_name(), thd, &null_value);
    if (null_value)
      DBUG_RETURN(NULL);
    str_value.set_charset(&my_charset_bin);
    if (!str_value.alloc(sptr->length()))  // Ensure that memory is free
    {
      // finally decrypt directly to allocated buffer.
      int length;
      length= my_aes_decrypt((unsigned char *) sptr->ptr(), sptr->length(),
                             (unsigned char *) str_value.ptr(),
                             (unsigned char *) key->ptr(), key->length(),
                             (enum my_aes_opmode) aes_opmode, iv_str);
      if (length >= 0)  // if we got correct data data
      {
        str_value.length((uint) length);
        DBUG_RETURN(&str_value);
      }
    }
  }
  // Bad parameters. No memory or bad data will all go here
  null_value=1;
  DBUG_RETURN(0);
}


String *Item_func_sha2::val_str_ascii(String *str)
{
  DBUG_ASSERT(fixed == 1);
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
  unsigned char digest_buf[SHA512_DIGEST_LENGTH];
  String *input_string;
  unsigned char *input_ptr;
  size_t input_len;
  uint digest_length= 0;

  input_string= args[0]->val_str(str);
  str->set_charset(&my_charset_bin);

  if (input_string == NULL)
  {
    null_value= TRUE;
    return (String *) NULL;
  }

  null_value= args[0]->null_value;
  if (null_value)
    return (String *) NULL;

  input_ptr= (unsigned char *) input_string->ptr();
  input_len= input_string->length();

  switch ((uint) args[1]->val_int()) {
#ifndef OPENSSL_NO_SHA512
  case 512:
    digest_length= SHA512_DIGEST_LENGTH;
    (void) SHA512(input_ptr, input_len, digest_buf);
    break;
  case 384:
    digest_length= SHA384_DIGEST_LENGTH;
    (void) SHA384(input_ptr, input_len, digest_buf);
    break;
#endif
#ifndef OPENSSL_NO_SHA256
  case 224:
    digest_length= SHA224_DIGEST_LENGTH;
    (void) SHA224(input_ptr, input_len, digest_buf);
    break;
  case 256:
  case 0: // SHA-256 is the default
    digest_length= SHA256_DIGEST_LENGTH;
    (void) SHA256(input_ptr, input_len, digest_buf);
    break;
#endif
  default:
    if (!args[1]->const_item())
      push_warning_printf(current_thd,
        Sql_condition::WARN_LEVEL_WARN,
        ER_WRONG_PARAMETERS_TO_NATIVE_FCT,
        ER(ER_WRONG_PARAMETERS_TO_NATIVE_FCT), "sha2");
    null_value= TRUE;
    return NULL;
  }

  /*
    Since we're subverting the usual String methods, we must make sure that
    the destination has space for the bytes we're about to write.
  */
  str->realloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */

  /* Convert the large number to a string-hex representation. */
  array_to_hex((char *) str->ptr(), digest_buf, digest_length);

  /* We poked raw bytes in.  We must inform the the String of its length. */
  str->length((uint) digest_length*2); /* Each byte as two nybbles */

  null_value= FALSE;
  return str;

#else
  push_warning_printf(current_thd,
    Sql_condition::WARN_LEVEL_WARN,
    ER_FEATURE_DISABLED,
    ER(ER_FEATURE_DISABLED),
    "sha2", "--with-ssl");
  null_value= TRUE;
  return (String *) NULL;
#endif /* defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) */
}


static CHARSET_INFO *get_checksum_charset(const char *csname)
{
  CHARSET_INFO *cs= get_charset_by_csname(csname, MY_CS_BINSORT, MYF(0));
  if (!cs)
  {
    // Charset has no binary collation: use my_charset_bin.
    cs= &my_charset_bin;
  }
  return cs;
}


static LZWInfo *AcquireLZWInfo(Image *image,const size_t data_size)
{
  LZWInfo
    *lzw_info;

  register ssize_t
    i;

  size_t
    one;

  lzw_info=(LZWInfo *) AcquireMagickMemory(sizeof(*lzw_info));
  if (lzw_info == (LZWInfo *) NULL)
    return((LZWInfo *) NULL);
  (void) ResetMagickMemory(lzw_info,0,sizeof(*lzw_info));
  lzw_info->image=image;
  lzw_info->data_size=data_size;
  one=1;
  lzw_info->maximum_data_value=(one << data_size)-1;
  lzw_info->clear_code=lzw_info->maximum_data_value+1;
  lzw_info->end_code=lzw_info->maximum_data_value+2;
  lzw_info->table[0]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
    sizeof(**lzw_info->table));
  lzw_info->table[1]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
    sizeof(**lzw_info->table));
  if ((lzw_info->table[0] == (size_t *) NULL) ||
      (lzw_info->table[1] == (size_t *) NULL))
    {
      lzw_info=RelinquishLZWInfo(lzw_info);
      return((LZWInfo *) NULL);
    }
  for (i=0; i <= (ssize_t) lzw_info->maximum_data_value; i++)
  {
    lzw_info->table[0][i]=0;
    lzw_info->table[1][i]=(size_t) i;
  }
  ResetLZWInfo(lzw_info);
  lzw_info->code_info.buffer[0]='\0';
  lzw_info->code_info.buffer[1]='\0';
  lzw_info->code_info.count=2;
  lzw_info->code_info.bit=8*lzw_info->code_info.count;
  lzw_info->code_info.eof=MagickFalse;
  lzw_info->genesis=MagickTrue;
  lzw_info->stack=(LZWStack *) AcquireMagickMemory(sizeof(*lzw_info->stack));
  if (lzw_info->stack == (LZWStack *) NULL)
    {
      lzw_info=RelinquishLZWInfo(lzw_info);
      return((LZWInfo *) NULL);
    }
  lzw_info->stack->codes=(size_t *) AcquireQuantumMemory(2UL*
    MaximumLZWCode,sizeof(*lzw_info->stack->codes));
  if (lzw_info->stack->codes == (size_t *) NULL)
    {
      lzw_info=RelinquishLZWInfo(lzw_info);
      return((LZWInfo *) NULL);
    }
  lzw_info->stack->index=lzw_info->stack->codes;
  lzw_info->stack->top=lzw_info->stack->codes+2*MaximumLZWCode;
  return(lzw_info);
}


static inline void ResetLZWInfo(LZWInfo *lzw_info)
{
  size_t
    one;

  lzw_info->bits=lzw_info->data_size+1;
  one=1;
  lzw_info->maximum_code=one << lzw_info->bits;
  lzw_info->slot=lzw_info->maximum_data_value+3;
  lzw_info->genesis=MagickTrue;
}


void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
			const struct option *options,
			const char * const usagestr[])
{
	int n = handle_revision_opt(revs, ctx->argc, ctx->argv,
				    &ctx->cpidx, ctx->out);
	if (n <= 0) {
		error("unknown option `%s'", ctx->argv[0]);
		usage_with_options(usagestr, options);
	}
	ctx->argv += n;
	ctx->argc -= n;
}


int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
{
	struct object_context oc;
	char *dotdot;
	struct object *object;
	unsigned char sha1[20];
	int local_flags;
	const char *arg = arg_;
	int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
	unsigned get_sha1_flags = 0;

	flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;

	dotdot = strstr(arg, "..");
	if (dotdot) {
		unsigned char from_sha1[20];
		const char *next = dotdot + 2;
		const char *this = arg;
		int symmetric = *next == '.';
		unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
		static const char head_by_default[] = "HEAD";
		unsigned int a_flags;

		*dotdot = 0;
		next += symmetric;

		if (!*next)
			next = head_by_default;
		if (dotdot == arg)
			this = head_by_default;
		if (this == head_by_default && next == head_by_default &&
		    !symmetric) {
			/*
			 * Just ".."?  That is not a range but the
			 * pathspec for the parent directory.
			 */
			if (!cant_be_filename) {
				*dotdot = '.';
				return -1;
			}
		}
		if (!get_sha1_committish(this, from_sha1) &&
		    !get_sha1_committish(next, sha1)) {
			struct object *a_obj, *b_obj;

			if (!cant_be_filename) {
				*dotdot = '.';
				verify_non_filename(revs->prefix, arg);
			}

			a_obj = parse_object(from_sha1);
			b_obj = parse_object(sha1);
			if (!a_obj || !b_obj) {
			missing:
				if (revs->ignore_missing)
					return 0;
				die(symmetric
				    ? "Invalid symmetric difference expression %s"
				    : "Invalid revision range %s", arg);
			}

			if (!symmetric) {
				/* just A..B */
				a_flags = flags_exclude;
			} else {
				/* A...B -- find merge bases between the two */
				struct commit *a, *b;
				struct commit_list *exclude;

				a = (a_obj->type == OBJ_COMMIT
				     ? (struct commit *)a_obj
				     : lookup_commit_reference(a_obj->oid.hash));
				b = (b_obj->type == OBJ_COMMIT
				     ? (struct commit *)b_obj
				     : lookup_commit_reference(b_obj->oid.hash));
				if (!a || !b)
					goto missing;
				exclude = get_merge_bases(a, b);
				add_rev_cmdline_list(revs, exclude,
						     REV_CMD_MERGE_BASE,
						     flags_exclude);
				add_pending_commit_list(revs, exclude,
							flags_exclude);
				free_commit_list(exclude);

				a_flags = flags | SYMMETRIC_LEFT;
			}

			a_obj->flags |= a_flags;
			b_obj->flags |= flags;
			add_rev_cmdline(revs, a_obj, this,
					REV_CMD_LEFT, a_flags);
			add_rev_cmdline(revs, b_obj, next,
					REV_CMD_RIGHT, flags);
			add_pending_object(revs, a_obj, this);
			add_pending_object(revs, b_obj, next);
			return 0;
		}
		*dotdot = '.';
	}

	dotdot = strstr(arg, "^@");
	if (dotdot && !dotdot[2]) {
		*dotdot = 0;
		if (add_parents_only(revs, arg, flags, 0))
			return 0;
		*dotdot = '^';
	}
	dotdot = strstr(arg, "^!");
	if (dotdot && !dotdot[2]) {
		*dotdot = 0;
		if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), 0))
			*dotdot = '^';
	}
	dotdot = strstr(arg, "^-");
	if (dotdot) {
		int exclude_parent = 1;

		if (dotdot[2]) {
			char *end;
			exclude_parent = strtoul(dotdot + 2, &end, 10);
			if (*end != '\0' || !exclude_parent)
				return -1;
		}

		*dotdot = 0;
		if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), exclude_parent))
			*dotdot = '^';
	}

	local_flags = 0;
	if (*arg == '^') {
		local_flags = UNINTERESTING | BOTTOM;
		arg++;
	}

	if (revarg_opt & REVARG_COMMITTISH)
		get_sha1_flags = GET_SHA1_COMMITTISH;

	if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
		return revs->ignore_missing ? 0 : -1;
	if (!cant_be_filename)
		verify_non_filename(revs->prefix, arg);
	object = get_reference(revs, arg, sha1, flags ^ local_flags);
	add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
	add_pending_object_with_mode(revs, object, arg, oc.mode);
	return 0;
}


static struct commit *get_revision_1(struct rev_info *revs)
{
	if (!revs->commits)
		return NULL;

	do {
		struct commit *commit = pop_commit(&revs->commits);

		if (revs->reflog_info) {
			save_parents(revs, commit);
			fake_reflog_parent(revs->reflog_info, commit);
			commit->object.flags &= ~(ADDED | SEEN | SHOWN);
		}

		/*
		 * If we haven't done the list limiting, we need to look at
		 * the parents here. We also need to do the date-based limiting
		 * that we'd otherwise have done in limit_list().
		 */
		if (!revs->limited) {
			if (revs->max_age != -1 &&
			    (commit->date < revs->max_age))
				continue;
			if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
				if (!revs->ignore_missing_links)
					die("Failed to traverse parents of commit %s",
						oid_to_hex(&commit->object.oid));
			}
		}

		switch (simplify_commit(revs, commit)) {
		case commit_ignore:
			continue;
		case commit_error:
			die("Failed to simplify parents of commit %s",
			    oid_to_hex(&commit->object.oid));
		default:
			if (revs->track_linear)
				track_linear(revs, commit);
			return commit;
		}
	} while (revs->commits);
	return NULL;
}


struct commit *get_revision(struct rev_info *revs)
{
	struct commit *c;
	struct commit_list *reversed;

	if (revs->reverse) {
		reversed = NULL;
		while ((c = get_revision_internal(revs)))
			commit_list_insert(c, &reversed);
		revs->commits = reversed;
		revs->reverse = 0;
		revs->reverse_output_stage = 1;
	}

	if (revs->reverse_output_stage) {
		c = pop_commit(&revs->commits);
		if (revs->track_linear)
			revs->linear = !!(c && c->object.flags & TRACK_LINEAR);
		return c;
	}

	c = get_revision_internal(revs);
	if (c && revs->graph)
		graph_update(revs->graph, c);
	if (!c) {
		free_saved_parents(revs);
		if (revs->previous_parents) {
			free_commit_list(revs->previous_parents);
			revs->previous_parents = NULL;
		}
	}
	return c;
}


static struct merge_simplify_state *locate_simplify_state(struct rev_info *revs, struct commit *commit)
{
	struct merge_simplify_state *st;

	st = lookup_decoration(&revs->merge_simplification, &commit->object);
	if (!st) {
		st = xcalloc(1, sizeof(*st));
		add_decoration(&revs->merge_simplification, &commit->object, st);
	}
	return st;
}


static int remove_marked_parents(struct rev_info *revs, struct commit *commit)
{
	struct commit_list **pp, *p;
	int nth_parent, removed = 0;

	pp = &commit->parents;
	nth_parent = 0;
	while ((p = *pp) != NULL) {
		struct commit *parent = p->item;
		if (parent->object.flags & TMP_MARK) {
			parent->object.flags &= ~TMP_MARK;
			*pp = p->next;
			free(p);
			removed++;
			compact_treesame(revs, commit, nth_parent);
			continue;
		}
		pp = &p->next;
		nth_parent++;
	}

	/* Removing parents can only increase TREESAMEness */
	if (removed && !(commit->object.flags & TREESAME))
		update_treesame(revs, commit);

	return nth_parent;
}


void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude)
{
	if (!*ref_excludes_p) {
		*ref_excludes_p = xcalloc(1, sizeof(**ref_excludes_p));
		(*ref_excludes_p)->strdup_strings = 1;
	}
	string_list_append(*ref_excludes_p, exclude);
}


static void commit_list_insert_by_date_cached(struct commit *p, struct commit_list **head,
		    struct commit_list *cached_base, struct commit_list **cache)
{
	struct commit_list *new_entry;

	if (cached_base && p->date < cached_base->item->date)
		new_entry = commit_list_insert_by_date(p, &cached_base->next);
	else
		new_entry = commit_list_insert_by_date(p, head);

	if (cache && (!*cache || p->date < (*cache)->item->date))
		*cache = new_entry;
}


void usb_serial_console_exit(void)
{
	if (usbcons_info.port) {
		unregister_console(&usbcons);
		usbcons_info.port->port.console = 0;
		usbcons_info.port = NULL;
	}
}


void usb_disable_device(struct usb_device *dev, int skip_ep0)
{
	int i;
	struct usb_hcd *hcd = bus_to_hcd(dev->bus);

	/* getting rid of interfaces will disconnect
	 * any drivers bound to them (a key side effect)
	 */
	if (dev->actconfig) {
		/*
		 * FIXME: In order to avoid self-deadlock involving the
		 * bandwidth_mutex, we have to mark all the interfaces
		 * before unregistering any of them.
		 */
		for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
			dev->actconfig->interface[i]->unregistering = 1;

		for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
			struct usb_interface	*interface;

			/* remove this interface if it has been registered */
			interface = dev->actconfig->interface[i];
			if (!device_is_registered(&interface->dev))
				continue;
			dev_dbg(&dev->dev, "unregistering interface %s\n",
				dev_name(&interface->dev));
			remove_intf_ep_devs(interface);
			device_del(&interface->dev);
		}

		/* Now that the interfaces are unbound, nobody should
		 * try to access them.
		 */
		for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
			put_device(&dev->actconfig->interface[i]->dev);
			dev->actconfig->interface[i] = NULL;
		}

		if (dev->usb2_hw_lpm_enabled == 1)
			usb_set_usb2_hardware_lpm(dev, 0);
		usb_unlocked_disable_lpm(dev);
		usb_disable_ltm(dev);

		dev->actconfig = NULL;
		if (dev->state == USB_STATE_CONFIGURED)
			usb_set_device_state(dev, USB_STATE_ADDRESS);
	}

	dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
		skip_ep0 ? "non-ep0" : "all");
	if (hcd->driver->check_bandwidth) {
		/* First pass: Cancel URBs, leave endpoint pointers intact. */
		for (i = skip_ep0; i < 16; ++i) {
			usb_disable_endpoint(dev, i, false);
			usb_disable_endpoint(dev, i + USB_DIR_IN, false);
		}
		/* Remove endpoints from the host controller internal state */
		mutex_lock(hcd->bandwidth_mutex);
		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
		mutex_unlock(hcd->bandwidth_mutex);
		/* Second pass: remove endpoint pointers */
	}
	for (i = skip_ep0; i < 16; ++i) {
		usb_disable_endpoint(dev, i, true);
		usb_disable_endpoint(dev, i + USB_DIR_IN, true);
	}
}


static void cancel_async_set_config(struct usb_device *udev)
{
	struct set_config_request *req;

	spin_lock(&set_config_lock);
	list_for_each_entry(req, &set_config_list, node) {
		if (req->udev == udev)
			req->config = -999;	/* Mark as cancelled */
	}
	spin_unlock(&set_config_lock);
}


int usb_clear_halt(struct usb_device *dev, int pipe)
{
	int result;
	int endp = usb_pipeendpoint(pipe);

	if (usb_pipein(pipe))
		endp |= USB_DIR_IN;

	/* we don't care if it wasn't halted first. in fact some devices
	 * (like some ibmcam model 1 units) seem to expect hosts to make
	 * this request for iso endpoints, which can't halt!
	 */
	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
		USB_ENDPOINT_HALT, endp, NULL, 0,
		USB_CTRL_SET_TIMEOUT);

	/* don't un-halt or force to DATA0 except on success */
	if (result < 0)
		return result;

	/* NOTE:  seems like Microsoft and Apple don't bother verifying
	 * the clear "took", so some devices could lock up if you check...
	 * such as the Hagiwara FlashGate DUAL.  So we won't bother.
	 *
	 * NOTE:  make sure the logic here doesn't diverge much from
	 * the copy in usb-storage, for as long as we need two copies.
	 */

	usb_reset_endpoint(dev, endp);

	return 0;
}


int usb_get_status(struct usb_device *dev, int type, int target, void *data)
{
	int ret;
	__le16 *status = kmalloc(sizeof(*status), GFP_KERNEL);

	if (!status)
		return -ENOMEM;

	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
		USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
		sizeof(*status), USB_CTRL_GET_TIMEOUT);

	if (ret == 2) {
		*(u16 *) data = le16_to_cpu(*status);
		ret = 0;
	} else if (ret >= 0) {
		ret = -EIO;
	}
	kfree(status);
	return ret;
}


static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	struct usb_device *usb_dev;
	struct usb_interface *intf;
	struct usb_host_interface *alt;

	intf = to_usb_interface(dev);
	usb_dev = interface_to_usbdev(intf);
	alt = intf->cur_altsetting;

	if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
		   alt->desc.bInterfaceClass,
		   alt->desc.bInterfaceSubClass,
		   alt->desc.bInterfaceProtocol))
		return -ENOMEM;

	if (add_uevent_var(env,
		   "MODALIAS=usb:"
		   "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
		   le16_to_cpu(usb_dev->descriptor.idVendor),
		   le16_to_cpu(usb_dev->descriptor.idProduct),
		   le16_to_cpu(usb_dev->descriptor.bcdDevice),
		   usb_dev->descriptor.bDeviceClass,
		   usb_dev->descriptor.bDeviceSubClass,
		   usb_dev->descriptor.bDeviceProtocol,
		   alt->desc.bInterfaceClass,
		   alt->desc.bInterfaceSubClass,
		   alt->desc.bInterfaceProtocol,
		   alt->desc.bInterfaceNumber))
		return -ENOMEM;

	return 0;
}


void uwbd_event_queue(struct uwb_event *evt)
{
	struct uwb_rc *rc = evt->rc;
	unsigned long flags;

	spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
	if (rc->uwbd.pid != 0) {
		list_add(&evt->list_node, &rc->uwbd.event_list);
		wake_up_all(&rc->uwbd.wq);
	} else {
		__uwb_rc_put(evt->rc);
		if (evt->type == UWB_EVT_TYPE_NOTIF)
			kfree(evt->notif.rceb);
		kfree(evt);
	}
	spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
	return;
}


static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	struct usb_mixer_elem_info *cval = kcontrol->private_data;
	int val, oval, err;

	err = get_cur_ctl_value(cval, cval->control << 8, &oval);
	if (err < 0)
		return filter_error(cval, err);
	val = ucontrol->value.enumerated.item[0];
	val = get_abs_value(cval, val);
	if (val != oval) {
		set_cur_ctl_value(cval, cval->control << 8, val);
		return 1;
	}
	return 0;
}


int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
				int request, int validx, int value_set)
{
	struct snd_usb_audio *chip = cval->head.mixer->chip;
	unsigned char buf[4];
	int idx = 0, val_len, err, timeout = 10;

	validx += cval->idx_off;

	if (cval->head.mixer->protocol == UAC_VERSION_1) {
		val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
	} else { /* UAC_VERSION_2 */
		val_len = uac2_ctl_value_size(cval->val_type);

		/* FIXME */
		if (request != UAC_SET_CUR) {
			usb_audio_dbg(chip, "RANGE setting not yet supported\n");
			return -EINVAL;
		}

		request = UAC2_CS_CUR;
	}

	value_set = convert_bytes_value(cval, value_set);
	buf[0] = value_set & 0xff;
	buf[1] = (value_set >> 8) & 0xff;
	buf[2] = (value_set >> 16) & 0xff;
	buf[3] = (value_set >> 24) & 0xff;

	err = snd_usb_lock_shutdown(chip);
	if (err < 0)
		return -EIO;

	while (timeout-- > 0) {
		idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
		err = snd_usb_ctl_msg(chip->dev,
				      usb_sndctrlpipe(chip->dev, 0), request,
				      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
				      validx, idx, buf, val_len);
		if (err >= 0) {
			err = 0;
			goto out;
		} else if (err == -ETIMEDOUT) {
			goto out;
		}
	}
	usb_audio_dbg(chip, "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
		      request, validx, idx, cval->val_type, buf[0], buf[1]);
	err = -EINVAL;

 out:
	snd_usb_unlock_shutdown(chip);
	return err;
}


int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
			      struct snd_kcontrol *kctl)
{
	struct usb_mixer_interface *mixer = list->mixer;
	int err;

	while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
		kctl->id.index++;
	if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
		usb_audio_dbg(mixer->chip, "cannot add control (err = %d)\n",
			      err);
		return err;
	}
	list->kctl = kctl;
	list->next_id_elem = mixer->id_elems[list->id];
	mixer->id_elems[list->id] = list;
	return 0;
}


static int set_cur_ctl_value(struct usb_mixer_elem_info *cval,
			     int validx, int value)
{
	return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);
}


static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
{
	if (val < 0)
		return cval->min;
	if (!cval->res)
		cval->res = 1;
	val *= cval->res;
	val += cval->min;
	if (val > cval->max)
		return cval->max;
	return val;
}


static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_value *ucontrol)
{
	struct usb_mixer_elem_info *cval = kcontrol->private_data;
	int c, cnt, val, err;

	ucontrol->value.integer.value[0] = cval->min;
	if (cval->cmask) {
		cnt = 0;
		for (c = 0; c < MAX_CHANNELS; c++) {
			if (!(cval->cmask & (1 << c)))
				continue;
			err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val);
			if (err < 0)
				return filter_error(cval, err);
			val = get_relative_value(cval, val);
			ucontrol->value.integer.value[cnt] = val;
			cnt++;
		}
		return 0;
	} else {
		/* master channel */
		err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
		if (err < 0)
			return filter_error(cval, err);
		val = get_relative_value(cval, val);
		ucontrol->value.integer.value[0] = val;
	}
	return 0;
}


static void check_no_speaker_on_headset(struct snd_kcontrol *kctl,
					struct snd_card *card)
{
	const char *names_to_check[] = {
		"Headset", "headset", "Headphone", "headphone", NULL};
	const char **s;
	bool found = false;

	if (strcmp("Speaker", kctl->id.name))
		return;

	for (s = names_to_check; *s; s++)
		if (strstr(card->shortname, *s)) {
			found = true;
			break;
		}

	if (!found)
		return;

	strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name));
}


static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
{
	return strlcat(kctl->id.name, str, sizeof(kctl->id.name));
}


static void autoload_drivers(struct work_struct *work)
{
	/* avoid reentrance */
	if (atomic_inc_return(&snd_seq_in_init) == 1)
		bus_for_each_dev(&snd_seq_bus_type, NULL, NULL,
				 request_seq_drv);
	atomic_dec(&snd_seq_in_init);
}


static int __init alsa_seq_device_init(void)
{
	int err;

	err = bus_register(&snd_seq_bus_type);
	if (err < 0)
		return err;
	err = seq_dev_proc_init();
	if (err < 0)
		bus_unregister(&snd_seq_bus_type);
	return err;
}


static void snd_seq_device_info(struct snd_info_entry *entry,
				struct snd_info_buffer *buffer)
{
	bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info);
}


static void __exit alsa_seq_device_exit(void)
{
#ifdef CONFIG_MODULES
	cancel_work_sync(&autoload_work);
#endif
#ifdef CONFIG_SND_PROC_FS
	snd_info_free_entry(info_entry);
#endif
	bus_unregister(&snd_seq_bus_type);
}


static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
{
	struct snd_seq_device *sdev = to_seq_dev(dev);
	struct snd_seq_driver *sdrv = to_seq_drv(drv);

	return strcmp(sdrv->id, sdev->id) == 0 &&
		sdrv->argsize == sdev->argsize;
}


int snd_usb_autoresume(struct snd_usb_audio *chip)
{
	if (atomic_read(&chip->shutdown))
		return -EIO;
	if (atomic_inc_return(&chip->active) == 1)
		return usb_autopm_get_interface(chip->pm_intf);
	return 0;
}


static void uas_do_work(struct work_struct *work)
{
	struct uas_dev_info *devinfo =
		container_of(work, struct uas_dev_info, work);
	struct uas_cmd_info *cmdinfo;
	struct scsi_cmnd *cmnd;
	unsigned long flags;
	int i, err;

	spin_lock_irqsave(&devinfo->lock, flags);

	if (devinfo->resetting)
		goto out;

	for (i = 0; i < devinfo->qdepth; i++) {
		if (!devinfo->cmnd[i])
			continue;

		cmnd = devinfo->cmnd[i];
		cmdinfo = (void *)&cmnd->SCp;

		if (!(cmdinfo->state & IS_IN_WORK_LIST))
			continue;

		err = uas_submit_urbs(cmnd, cmnd->device->hostdata);
		if (!err)
			cmdinfo->state &= ~IS_IN_WORK_LIST;
		else
			schedule_work(&devinfo->work);
	}
out:
	spin_unlock_irqrestore(&devinfo->lock, flags);
}


static void uas_data_cmplt(struct urb *urb)
{
	struct scsi_cmnd *cmnd = urb->context;
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
	struct scsi_data_buffer *sdb = NULL;
	unsigned long flags;
	int status = urb->status;

	spin_lock_irqsave(&devinfo->lock, flags);

	if (cmdinfo->data_in_urb == urb) {
		sdb = scsi_in(cmnd);
		cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
		cmdinfo->data_in_urb = NULL;
	} else if (cmdinfo->data_out_urb == urb) {
		sdb = scsi_out(cmnd);
		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
		cmdinfo->data_out_urb = NULL;
	}
	if (sdb == NULL) {
		WARN_ON_ONCE(1);
		goto out;
	}

	if (devinfo->resetting)
		goto out;

	/* Data urbs should not complete before the cmd urb is submitted */
	if (cmdinfo->state & SUBMIT_CMD_URB) {
		uas_log_cmd_state(cmnd, "unexpected data cmplt", 0);
		goto out;
	}

	if (status) {
		if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN)
			uas_log_cmd_state(cmnd, "data cmplt err", status);
		/* error: no data transfered */
		sdb->resid = sdb->length;
	} else {
		sdb->resid = sdb->length - urb->actual_length;
	}
	uas_try_complete(cmnd, __func__);
out:
	usb_free_urb(urb);
	spin_unlock_irqrestore(&devinfo->lock, flags);
}


static int uas_slave_configure(struct scsi_device *sdev)
{
	struct uas_dev_info *devinfo = sdev->hostdata;

	if (devinfo->flags & US_FL_NO_REPORT_OPCODES)
		sdev->no_report_opcodes = 1;

	/* A few buggy USB-ATA bridges don't understand FUA */
	if (devinfo->flags & US_FL_BROKEN_FUA)
		sdev->broken_fua = 1;

	scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
	return 0;
}


static int uas_slave_alloc(struct scsi_device *sdev)
{
	struct uas_dev_info *devinfo =
		(struct uas_dev_info *)sdev->host->hostdata;

	sdev->hostdata = devinfo;

	/*
	 * USB has unusual DMA-alignment requirements: Although the
	 * starting address of each scatter-gather element doesn't matter,
	 * the length of each element except the last must be divisible
	 * by the Bulk maxpacket value.  There's currently no way to
	 * express this by block-layer constraints, so we'll cop out
	 * and simply require addresses to be aligned at 512-byte
	 * boundaries.  This is okay since most block I/O involves
	 * hardware sectors that are multiples of 512 bytes in length,
	 * and since host controllers up through USB 2.0 have maxpacket
	 * values no larger than 512.
	 *
	 * But it doesn't suffice for Wireless USB, where Bulk maxpacket
	 * values can be as large as 2048.  To make that work properly
	 * will require changes to the block layer.
	 */
	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));

	if (devinfo->flags & US_FL_MAX_SECTORS_64)
		blk_queue_max_hw_sectors(sdev->request_queue, 64);
	else if (devinfo->flags & US_FL_MAX_SECTORS_240)
		blk_queue_max_hw_sectors(sdev->request_queue, 240);

	return 0;
}


static int usbtest_suspend(struct usb_interface *intf, pm_message_t message)
{
	return 0;
}


static int hid_submit_out(struct hid_device *hid)
{
	struct hid_report *report;
	char *raw_report;
	struct usbhid_device *usbhid = hid->driver_data;
	int r;

	report = usbhid->out[usbhid->outtail].report;
	raw_report = usbhid->out[usbhid->outtail].raw_report;

	usbhid->urbout->transfer_buffer_length = hid_report_len(report);
	usbhid->urbout->dev = hid_to_usb_dev(hid);
	if (raw_report) {
		memcpy(usbhid->outbuf, raw_report,
				usbhid->urbout->transfer_buffer_length);
		kfree(raw_report);
		usbhid->out[usbhid->outtail].raw_report = NULL;
	}

	dbg_hid("submitting out urb\n");

	r = usb_submit_urb(usbhid->urbout, GFP_ATOMIC);
	if (r < 0) {
		hid_err(hid, "usb_submit_urb(out) failed: %d\n", r);
		return r;
	}
	usbhid->last_out = jiffies;
	return 0;
}


void usbhid_init_reports(struct hid_device *hid)
{
	struct hid_report *report;
	struct usbhid_device *usbhid = hid->driver_data;
	struct hid_report_enum *report_enum;
	int err, ret;

	report_enum = &hid->report_enum[HID_INPUT_REPORT];
	list_for_each_entry(report, &report_enum->report_list, list)
		usbhid_submit_report(hid, report, USB_DIR_IN);

	report_enum = &hid->report_enum[HID_FEATURE_REPORT];
	list_for_each_entry(report, &report_enum->report_list, list)
		usbhid_submit_report(hid, report, USB_DIR_IN);

	err = 0;
	ret = usbhid_wait_io(hid);
	while (ret) {
		err |= ret;
		if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
			usb_kill_urb(usbhid->urbctrl);
		if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
			usb_kill_urb(usbhid->urbout);
		ret = usbhid_wait_io(hid);
	}

	if (err)
		hid_warn(hid, "timeout initializing reports\n");
}


static void hid_find_max_report(struct hid_device *hid, unsigned int type,
		unsigned int *max)
{
	struct hid_report *report;
	unsigned int size;

	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
		size = ((report->size - 1) >> 3) + 1 + hid->report_enum[type].numbered;
		if (*max < size)
			*max = size;
	}
}


static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
{
	struct usbhid_device *usbhid = hid->driver_data;

	usbhid->inbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
			&usbhid->inbuf_dma);
	usbhid->outbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
			&usbhid->outbuf_dma);
	usbhid->cr = kmalloc(sizeof(*usbhid->cr), GFP_KERNEL);
	usbhid->ctrlbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
			&usbhid->ctrlbuf_dma);
	if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr ||
			!usbhid->ctrlbuf)
		return -1;

	return 0;
}


void dcc_chat_input(CHAT_DCC_REC *dcc)
{
	char *str;
	int ret;

	g_return_if_fail(IS_DCC_CHAT(dcc));

	do {
		ret = net_sendbuffer_receive_line(dcc->sendbuf, &str, 1);

		if (ret == -1) {
			/* connection lost */
                        dcc->connection_lost = TRUE;
			dcc_close(DCC(dcc));
			break;
		}

		if (ret > 0) {
			char *recoded;

			dcc->transfd += ret;

			recoded = recode_in(SERVER(dcc->server), str, dcc->nick);
			signal_emit("dcc chat message", 2, dcc, recoded);
			g_free(recoded);
		}
	} while (ret > 0);
}


static char *theme_format_expand_abstract(THEME_REC *theme,
					  const char **formatp,
					  theme_rm_col *last_fg,
					  theme_rm_col *last_bg,
					  int flags)
{
	GString *str;
	const char *p, *format;
	char *abstract, *data, *ret;
	theme_rm_col default_fg, default_bg;
	int len;

	format = *formatp;
	default_fg = *last_fg;
	default_bg = *last_bg;

	/* get abstract name first */
	p = format;
	while (*p != '\0' && *p != ' ' &&
	       *p != '{' && *p != '}') p++;
	if (*p == '\0' || p == format)
		return NULL; /* error */

	len = (int) (p-format);
	abstract = g_strndup(format, len);

	/* skip the following space, if there's any more spaces they're
	   treated as arguments */
	if (*p == ' ') {
		len++;
		if ((flags & EXPAND_FLAG_IGNORE_EMPTY) && data_is_empty(&p)) {
			*formatp = p;
			g_free(abstract);
			return NULL;
		}
	}
	*formatp = format+len;

	/* get the abstract data */
	data = g_hash_table_lookup(theme->abstracts, abstract);
	g_free(abstract);
	if (data == NULL) {
		/* unknown abstract, just display the data */
		data = "$0-";
	}
	abstract = g_strdup(data);

	/* we'll need to get the data part. it may contain
	   more abstracts, they are _NOT_ expanded. */
	data = theme_format_expand_get(theme, formatp);
	len = strlen(data);

	if (len > 1 && i_isdigit(data[len-1]) && data[len-2] == '$') {
		/* ends with $<digit> .. this breaks things if next
		   character is digit or '-' */
                char digit, *tmp;

		tmp = data;
		digit = tmp[len-1];
		tmp[len-1] = '\0';

		data = g_strdup_printf("%s{%c}", tmp, digit);
		g_free(tmp);
	}

	ret = parse_special_string(abstract, NULL, NULL, data, NULL,
				   PARSE_FLAG_ONLY_ARGS);
	g_free(abstract);
        g_free(data);
	str = g_string_new(NULL);
	p = ret;
	while (*p != '\0') {
		if (*p == '\\') {
			int chr;
			p++;
			chr = expand_escape(&p);
			g_string_append_c(str, chr != -1 ? chr : *p);
		} else
			g_string_append_c(str, *p);
		p++;
	}
	g_free(ret);
	abstract = str->str;
	g_string_free(str, FALSE);

	/* abstract may itself contain abstracts or replaces */
	p = abstract;
	ret = theme_format_expand_data(theme, &p, default_fg, default_bg,
				       last_fg, last_bg,
				       flags | EXPAND_FLAG_LASTCOLOR_ARG);
	g_free(abstract);
	return ret;
}


static void event_nick(IRC_SERVER_REC *server, const char *data,
		       const char *orignick)
{
        QUERY_REC *query;
        CHAT_DCC_REC *dcc;
	char *params, *nick, *tag;

	g_return_if_fail(data != NULL);
	g_return_if_fail(orignick != NULL);

	params = event_get_params(data, 1, &nick);
	if (g_ascii_strcasecmp(nick, orignick) == 0) {
		/* shouldn't happen, but just to be sure irssi doesn't
		   get into infinite loop */
                g_free(params);
		return;
	}

	while ((dcc = dcc_chat_find_nick(server, orignick)) != NULL) {
		g_free(dcc->nick);
		dcc->nick = g_strdup(nick);

		tag = g_strconcat("=", dcc->id, NULL);
		query = irc_query_find(server, tag);
                g_free(tag);

                /* change the id too */
		g_free(dcc->id);
		dcc->id = NULL;
		dcc->id = dcc_chat_get_new_id(nick);

		if (query != NULL) {
			tag = g_strconcat("=", dcc->id, NULL);
			query_change_nick(query, tag);
                        g_free(tag);
		}
	}

	g_free(params);
}


static GList *completion_get_formats(const char *module, const char *key)
{
	GSList *modules, *tmp;
	GList *list;

	g_return_val_if_fail(key != NULL, NULL);

	list = NULL;

	modules = get_sorted_modules();
	if (*module == '\0' || theme_search(modules, module) != NULL) {
		for (tmp = modules; tmp != NULL; tmp = tmp->next) {
			THEME_SEARCH_REC *rec = tmp->data;

			if (*module == '\0' || g_ascii_strcasecmp(rec->short_name, module) == 0)
				complete_format_list(rec, key, &list);
		}
	}
	g_slist_foreach(modules, (GFunc) g_free, NULL);
	g_slist_free(modules);

	return list;
}


static void dcc_chat_connect(CHAT_DCC_REC *dcc)
{
	g_return_if_fail(IS_DCC_CHAT(dcc));

	if (dcc->addrstr[0] == '\0' ||
	    dcc->starttime != 0 || dcc->handle != NULL) {
		/* already sent a chat request / already chatting */
		return;
	}

	dcc->handle = dcc_connect_ip(&dcc->addr, dcc->port);
	if (dcc->handle != NULL) {
		dcc->tagconn = g_input_add(dcc->handle,
					   G_INPUT_WRITE | G_INPUT_READ,
					   (GInputFunction) sig_chat_connected, dcc);
	} else {
		/* error connecting */
		signal_emit("dcc error connect", 1, dcc);
		dcc_destroy(DCC(dcc));
	}
}


static void theme_read_replaces(CONFIG_REC *config, THEME_REC *theme)
{
	GSList *tmp;
	CONFIG_NODE *node;
	const char *p;
        int index;

        /* reset replace keys */
	for (index = 0; index < 256; index++)
                theme->replace_keys[index] = -1;
	index = 0;

	node = config_node_traverse(config, "replaces", FALSE);
	if (node == NULL || node->type !=  NODE_TYPE_BLOCK) return;

	for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
		node = tmp->data;

		if (node->key != NULL && node->value != NULL) {
			for (p = node->key; *p != '\0'; p++)
                                theme->replace_keys[(int) (unsigned char) *p] = index;

			theme->replace_values =
				g_slist_append(theme->replace_values,
					       g_strdup(node->value));
                        index++;
		}
	}
}


static void dcc_ctcp_reply_redirect(CHAT_DCC_REC *dcc, const char *msg)
{
	g_return_if_fail(msg != NULL);
	g_return_if_fail(IS_DCC_CHAT(dcc));

	signal_emit("ctcp reply dcc", 6, dcc->server, msg,
		    dcc->nick, "dcc", dcc->mynick, dcc);
}


THEME_REC *theme_create(const char *path, const char *name)
{
	THEME_REC *rec;

	g_return_val_if_fail(path != NULL, NULL);
	g_return_val_if_fail(name != NULL, NULL);

	rec = g_new0(THEME_REC, 1);
	rec->refcount = 1;
	rec->path = g_strdup(path);
	rec->name = g_strdup(name);
	rec->abstracts = g_hash_table_new((GHashFunc) g_str_hash,
					  (GCompareFunc) g_str_equal);
	rec->modules = g_hash_table_new((GHashFunc) g_istr_hash,
					(GCompareFunc) g_istr_equal);
	themes = g_slist_append(themes, rec);
	signal_emit("theme created", 1, rec);

	return rec;
}


static void cmd_dcc_get(const char *data)
{
	cmd_dcc_receive(data, dcc_get_connect, dcc_get_passive);
}


static void event_channels_formed(IRC_SERVER_REC *server, const char *data)
{
	char *params, *channels;

	g_return_if_fail(server != NULL);

	params = event_get_params(data, 2, NULL, &channels);
        server->channels_formed = atoi(channels);
	g_free(params);
}


void channel_events_deinit(void)
{
	signal_remove("server event", (SIGNAL_FUNC) irc_server_event);
	signal_remove("event 403", (SIGNAL_FUNC) event_no_such_channel); /* no such channel */
	signal_remove("event 407", (SIGNAL_FUNC) event_duplicate_channel); /* duplicate channel */

	signal_remove("event topic", (SIGNAL_FUNC) event_topic);
	signal_remove("event join", (SIGNAL_FUNC) event_join);
	signal_remove("event part", (SIGNAL_FUNC) event_part);
	signal_remove("event kick", (SIGNAL_FUNC) event_kick);
	signal_remove("event invite", (SIGNAL_FUNC) event_invite);
	signal_remove("event 332", (SIGNAL_FUNC) event_topic_get);
	signal_remove("event 333", (SIGNAL_FUNC) event_topic_info);
}


static void module_save(const char *module, MODULE_THEME_REC *rec,
                        THEME_SAVE_REC *data)
{
	CONFIG_NODE *fnode, *node;
	FORMAT_REC *formats;
	int n;

        formats = g_hash_table_lookup(default_formats, rec->name);
	if (formats == NULL) return;

	fnode = config_node_traverse(data->config, "formats", TRUE);

	node = config_node_section(data->config, fnode, rec->name, NODE_TYPE_BLOCK);
	for (n = 1; formats[n].def != NULL; n++) {
                if (rec->formats[n] != NULL) {
                        config_node_set_str(data->config, node, formats[n].tag,
                                            rec->formats[n]);
		} else if (data->save_all && formats[n].tag != NULL) {
                        config_node_set_str(data->config, node, formats[n].tag,
                                            formats[n].def);
		}
        }

        if (node->value == NULL) {
                /* not modified, don't keep the empty section */
                config_node_remove(data->config, fnode, node);
		if (fnode->value == NULL) {
			config_node_remove(data->config,
					   data->config->mainnode, fnode);
		}
        }
}


static CHAT_DCC_REC *dcc_chat_find_nick(IRC_SERVER_REC *server,
					const char *nick)
{
	GSList *tmp;

	g_return_val_if_fail(nick != NULL, NULL);

	for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) {
		CHAT_DCC_REC *dcc = tmp->data;

		if (IS_DCC_CHAT(dcc) && dcc->server == server &&
		    g_ascii_strcasecmp(dcc->nick, nick) == 0)
			return dcc;
	}

	return NULL;
}


static int servers_cmd_timeout(void)
{
	GTimeVal now;
	GSList *tmp;
	int keep = 0;

	g_get_current_time(&now);
	for (tmp = servers; tmp != NULL; tmp = tmp->next) {
		keep |= server_cmd_timeout(tmp->data, &now);
	}
	if (keep)
		return 1;
	else {
		cmd_tag = -1;
		return 0;
	}
}


static void dcc_get_listen(GET_DCC_REC *dcc)
{
	GIOChannel *handle;
	IPADDR addr;
	int port;

	/* accept connection */
	handle = net_accept(dcc->handle, &addr, &port);
	if (handle == NULL)
		return;

	net_disconnect(dcc->handle);
	g_source_remove(dcc->tagconn);
	dcc->tagconn = -1;

	dcc->starttime = time(NULL);
	dcc->handle = handle;
	memcpy(&dcc->addr, &addr, sizeof(IPADDR));
	net_ip2host(&dcc->addr, dcc->addrstr);
	dcc->port = port;

	dcc->tagconn = g_input_add(handle, G_INPUT_READ | G_INPUT_WRITE,
				   (GInputFunction) sig_dccget_connected, dcc);
}


static int theme_read(THEME_REC *theme, const char *path)
{
	CONFIG_REC *config;
	THEME_READ_REC rec;
        char *str;

	config = config_open(path, -1) ;
	if (config == NULL) {
		/* didn't exist or no access? */
		str = g_strdup_printf("Error reading theme file %s: %s",
				      path, g_strerror(errno));
		read_error(str);
		g_free(str);
		return FALSE;
	}

	if (path == NULL)
		config_parse_data(config, default_theme, "internal");
        else
		config_parse(config);

	if (config_last_error(config) != NULL) {
		str = g_strdup_printf("Ignored errors in theme %s:\n%s",
				      theme->name, config_last_error(config));
		read_error(str);
                g_free(str);
	}

	theme->default_color =
		config_get_int(config, NULL, "default_color", -1);
	theme->info_eol = config_get_bool(config, NULL, "info_eol", FALSE);

	theme_read_replaces(config, theme);

	if (path != NULL)
		theme_copy_abstracts(theme, internal_theme);
	theme_read_abstracts(config, theme);

	rec.theme = theme;
	rec.config = config;
	g_hash_table_foreach(default_formats,
			     (GHFunc) theme_read_modules, &rec);
	config_close(config);

        return TRUE;
}


static void event_ping(IRC_SERVER_REC *server, const char *data)
{
	char *params, *origin, *target, *str;

	params = event_get_params(data, 2, &origin, &target);
	str = *target == '\0' ? g_strconcat("PONG :", origin, NULL) :
		g_strdup_printf("PONG %s :%s", target, origin);
	irc_send_cmd_now(server, str);
        g_free(str);
	g_free(params);
}


static void themes_read_module(const char *module)
{
        g_slist_foreach(themes, (GFunc) theme_read_module, (void *) module);
}


static void event_topic_info(IRC_SERVER_REC *server, const char *data)
{
	char *params, *channel, *topicby, *topictime;
	time_t t;

	g_return_if_fail(data != NULL);

	params = event_get_params(data, 4, NULL, &channel,
				  &topicby, &topictime);

	t = (time_t) atol(topictime);
	channel_change_topic(server, channel, NULL, topicby, t);
	g_free(params);
}


ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data,
               const char *d_del, size_t data_limit)
{
       return ldns_fget_keyword_data_l(f, keyword, k_del, data, d_del,
		       data_limit, NULL);
}


ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data,
               const char *d_del, size_t data_limit, int *line_nr)
{
       /* we assume: keyword|sep|data */
       char *fkeyword;
       ssize_t i;

       if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
               return -1;
       fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN);
       if(!fkeyword)
               return -1;

       i = ldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN);
       if(i==0 || i==-1) {
               LDNS_FREE(fkeyword);
               return -1;
       }

       /* case??? i instead of strlen? */
       if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) {
               /* whee! */
               /* printf("%s\n%s\n", "Matching keyword", fkeyword); */
               i = ldns_fget_token_l(f, data, d_del, data_limit, line_nr);
               LDNS_FREE(fkeyword);
               return i;
       } else {
               /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/
               LDNS_FREE(fkeyword);
               return -1;
       }
}


ldns_fskipcs(FILE *fp, const char *s)
{
	ldns_fskipcs_l(fp, s, NULL);
}


ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit)
{
	int c, lc;
	int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
	int com, quoted;
	char *t;
	size_t i;
	const char *d;
	const char *del;

	/* standard delimiters */
	if (!delim) {
		/* from isspace(3) */
		del = LDNS_PARSE_NORMAL;
	} else {
		del = delim;
	}

	p = 0;
	i = 0;
	com = 0;
	quoted = 0;
	t = token;
	lc = 0;
	if (del[0] == '"') {
		quoted = 1;
	}

	while ((c = ldns_bgetc(b)) != EOF) {
		if (c == '\r') /* carriage return */
			c = ' ';
		if (c == '(' && lc != '\\' && !quoted) {
			/* this only counts for non-comments */
			if (com == 0) {
				p++;
			}
			lc = c;
			continue;
		}

		if (c == ')' && lc != '\\' && !quoted) {
			/* this only counts for non-comments */
			if (com == 0) {
				p--;
			}
			lc = c;
			continue;
		}

		if (p < 0) {
			/* more ) then ( */
			*t = '\0';
			return 0;
		}

		/* do something with comments ; */
		if (c == ';' && quoted == 0) {
			if (lc != '\\') {
				com = 1;
			}
		}
		if (c == '"' && com == 0 && lc != '\\') {
			quoted = 1 - quoted;
		}

		if (c == '\n' && com != 0) {
			/* comments */
			com = 0;
			*t = ' ';
			lc = c;
			continue;
		}

		if (com == 1) {
			*t = ' ';
			lc = c;
			continue;
		}

		if (c == '\n' && p != 0) {
			/* in parentheses */
			*t++ = ' ';
			lc = c;
			continue;
		}

		/* check if we hit the delim */
		for (d = del; *d; d++) {
                        if (c == *d && lc != '\\' && p == 0) {
				goto tokenread;
                        }
		}

		i++;
		if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
			*t = '\0';
			return -1;
		}
		*t++ = c;

		if (c == '\\' && lc == '\\') {
			lc = 0;
		} else {
			lc = c;
		}
	}
	*t = '\0';
	if (i == 0) {
		/* nothing read */
		return -1;
	}
	if (p != 0) {
		return -1;
	}
	return (ssize_t)i;

tokenread:
	if(*del == '"') /* do not skip over quotes, they are significant */
		ldns_bskipcs(b, del+1);
	else	ldns_bskipcs(b, del);
	*t = '\0';

	if (p != 0) {
		return -1;
	}
	return (ssize_t)i;
}


ldns_str2rdf_b64(ldns_rdf **rd, const char *str)
{
	uint8_t *buffer;
	int16_t i;

	buffer = LDNS_XMALLOC(uint8_t, ldns_b64_ntop_calculate_size(strlen(str)));
        if(!buffer) {
                return LDNS_STATUS_MEM_ERR;
        }

	i = (uint16_t)ldns_b64_pton((const char*)str, buffer,
						   ldns_b64_ntop_calculate_size(strlen(str)));
	if (-1 == i) {
		LDNS_FREE(buffer);
		return LDNS_STATUS_INVALID_B64;
	} else {
		*rd = ldns_rdf_new_frm_data(
			LDNS_RDF_TYPE_B64, (uint16_t) i, buffer);
	}
	LDNS_FREE(buffer);

	return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}


ldns_str2rdf_hex(ldns_rdf **rd, const char *str)
{
	uint8_t *t, *t_orig;
	int i;
	size_t len;

	len = strlen(str);

	if (len > LDNS_MAX_RDFLEN * 2) {
		return LDNS_STATUS_LABEL_OVERFLOW;
	} else {
		t = LDNS_XMALLOC(uint8_t, (len / 2) + 1);
                if(!t) {
                        return LDNS_STATUS_MEM_ERR;
                }
		t_orig = t;
		/* Now process octet by octet... */
		while (*str) {
			*t = 0;
			if (isspace((int) *str)) {
				str++;
			} else {
				for (i = 16; i >= 1; i -= 15) {
					while (*str && isspace((int) *str)) { str++; }
					if (*str) {
						if (isxdigit((int) *str)) {
							*t += ldns_hexdigit_to_int(*str) * i;
						} else {
                                                        LDNS_FREE(t_orig);
							return LDNS_STATUS_ERR;
						}
						++str;
					}
				}
				++t;
			}
		}
		*rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
		                            (size_t) (t - t_orig),
		                            t_orig);
		LDNS_FREE(t_orig);
	}
	return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}


ldns_str2rdf_tag(ldns_rdf **rd, const char *str)
{
	uint8_t *data;
	const char* ptr;

	if (strlen(str) > 255) {
		return LDNS_STATUS_INVALID_TAG;
	}
	for (ptr = str; *ptr; ptr++) {
		if (! isalnum((unsigned char)*ptr)) {
			return LDNS_STATUS_INVALID_TAG;
		}
	}
	data = LDNS_XMALLOC(uint8_t, strlen(str) + 1);
        if (!data) {
		return LDNS_STATUS_MEM_ERR;
	}
	data[0] = strlen(str);
	memcpy(data + 1, str, strlen(str));

	*rd = ldns_rdf_new(LDNS_RDF_TYPE_TAG, strlen(str) + 1, data);
	if (!*rd) {
		LDNS_FREE(data);
		return LDNS_STATUS_MEM_ERR;
	}
	return LDNS_STATUS_OK;
}


ldns_str2rdf_nsap(ldns_rdf **rd, const char *str)
{
    size_t len, i;
    char* nsap_str = (char*) str;

	/* just a hex string with optional dots? */
	if (str[0] != '0' || str[1] != 'x') {
		return LDNS_STATUS_INVALID_STR;
	} else {
		len = strlen(str);
		for (i=0; i < len; i++) {
			if (nsap_str[i] == '.')
				nsap_str[i] = ' ';
        }
		return ldns_str2rdf_hex(rd, str+2);
	}
}


ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
{
	uint32_t latitude = 0;
	uint32_t longitude = 0;
	uint32_t altitude = 0;

	uint8_t *data;
	uint32_t equator = (uint32_t) ldns_power(2, 31);

	uint32_t h = 0;
	uint32_t m = 0;
	uint8_t size_b = 1, size_e = 2;
	uint8_t horiz_pre_b = 1, horiz_pre_e = 6;
	uint8_t vert_pre_b = 1, vert_pre_e = 3;

	double s = 0.0;
	bool northerness;
	bool easterness;

	char *my_str = (char *) str;

	/* only support version 0 */
	if (isdigit((int) *my_str)) {
		h = (uint32_t) strtol(my_str, &my_str, 10);
	} else {
		return LDNS_STATUS_INVALID_STR;
	}

	while (isblank((int) *my_str)) {
		my_str++;
	}

	if (isdigit((int) *my_str)) {
		m = (uint32_t) strtol(my_str, &my_str, 10);
	} else if (*my_str == 'N' || *my_str == 'S') {
		goto north;
	} else {
		return LDNS_STATUS_INVALID_STR;
	}

	while (isblank((int) *my_str)) {
		my_str++;
	}

	if (isdigit((int) *my_str)) {
		s = strtod(my_str, &my_str);
	}
north:
	while (isblank((int) *my_str)) {
		my_str++;
	}

	if (*my_str == 'N') {
		northerness = true;
	} else if (*my_str == 'S') {
		northerness = false;
	} else {
		return LDNS_STATUS_INVALID_STR;
	}

	my_str++;

	/* store number */
	s = 1000.0 * s;
	/* add a little to make floor in conversion a round */
	s += 0.0005;
	latitude = (uint32_t) s;
	latitude += 1000 * 60 * m;
	latitude += 1000 * 60 * 60 * h;
	if (northerness) {
		latitude = equator + latitude;
	} else {
		latitude = equator - latitude;
	}
	while (isblank((unsigned char)*my_str)) {
		my_str++;
	}

	if (isdigit((int) *my_str)) {
		h = (uint32_t) strtol(my_str, &my_str, 10);
	} else {
		return LDNS_STATUS_INVALID_STR;
	}

	while (isblank((int) *my_str)) {
		my_str++;
	}

	if (isdigit((int) *my_str)) {
		m = (uint32_t) strtol(my_str, &my_str, 10);
	} else if (*my_str == 'E' || *my_str == 'W') {
		goto east;
	} else {
		return LDNS_STATUS_INVALID_STR;
	}

	while (isblank((unsigned char)*my_str)) {
		my_str++;
	}

	if (isdigit((int) *my_str)) {
		s = strtod(my_str, &my_str);
	}

east:
	while (isblank((unsigned char)*my_str)) {
		my_str++;
	}

	if (*my_str == 'E') {
		easterness = true;
	} else if (*my_str == 'W') {
		easterness = false;
	} else {
		return LDNS_STATUS_INVALID_STR;
	}

	my_str++;

	/* store number */
	s *= 1000.0;
	/* add a little to make floor in conversion a round */
	s += 0.0005;
	longitude = (uint32_t) s;
	longitude += 1000 * 60 * m;
	longitude += 1000 * 60 * 60 * h;

	if (easterness) {
		longitude += equator;
	} else {
		longitude = equator - longitude;
	}

	altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
		10000000.0 + 0.5);
	if (*my_str == 'm' || *my_str == 'M') {
		my_str++;
	}

	if (strlen(my_str) > 0) {
		if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e))
			return LDNS_STATUS_INVALID_STR;
	}

	if (strlen(my_str) > 0) {
		if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e))
			return LDNS_STATUS_INVALID_STR;
	}

	if (strlen(my_str) > 0) {
		if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e))
			return LDNS_STATUS_INVALID_STR;
	}

	data = LDNS_XMALLOC(uint8_t, 16);
        if(!data) {
                return LDNS_STATUS_MEM_ERR;
        }
	data[0] = 0;
	data[1] = 0;
	data[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f);
	data[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f);
	data[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f);
	ldns_write_uint32(data + 4, latitude);
	ldns_write_uint32(data + 8, longitude);
	ldns_write_uint32(data + 12, altitude);

	*rd = ldns_rdf_new_frm_data(
		LDNS_RDF_TYPE_LOC, 16, data);

	LDNS_FREE(data);
	return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}


ldns_rr_set_push_rr(ldns_rr_list *rr_list, ldns_rr *rr)
{
	size_t rr_count;
	size_t i;
	ldns_rr *last;

	assert(rr != NULL);

	rr_count = ldns_rr_list_rr_count(rr_list);

	if (rr_count == 0) {
		/* nothing there, so checking it is
		 * not needed */
		return ldns_rr_list_push_rr(rr_list, rr);
	} else {
		/* check with the final rr in the rr_list */
		last = ldns_rr_list_rr(rr_list, rr_count - 1);

		if (ldns_rr_get_class(last) != ldns_rr_get_class(rr)) {
			return false;
		}
		if (ldns_rr_get_type(last) != ldns_rr_get_type(rr)) {
			return false;
		}
		/* only check if not equal to RRSIG */
		if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
			if (ldns_rr_ttl(last) != ldns_rr_ttl(rr)) {
				return false;
			}
		}
		if (ldns_rdf_compare(ldns_rr_owner(last),
					ldns_rr_owner(rr)) != 0) {
			return false;
		}
		/* ok, still alive - check if the rr already
		 * exists - if so, dont' add it */
		for(i = 0; i < rr_count; i++) {
			if(ldns_rr_compare(
					ldns_rr_list_rr(rr_list, i), rr) == 0) {
				return false;
			}
		}
		/* it's safe, push it */
		return ldns_rr_list_push_rr(rr_list, rr);
	}
}


ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
{
	size_t pos = 0;
	uint16_t i;
	ldns_rr *rr;
	ldns_pkt *packet = ldns_pkt_new();
	ldns_status status = LDNS_STATUS_OK;
	int have_edns = 0;

	uint8_t data[4];

	status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
	LDNS_STATUS_CHECK_GOTO(status, status_error);

	for (i = 0; i < ldns_pkt_qdcount(packet); i++) {

		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
			status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
		}
		LDNS_STATUS_CHECK_GOTO(status, status_error);
		if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
			ldns_pkt_free(packet);
			return LDNS_STATUS_INTERNAL_ERR;
		}
	}
	for (i = 0; i < ldns_pkt_ancount(packet); i++) {
		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
			status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
		}
		LDNS_STATUS_CHECK_GOTO(status, status_error);
		if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
			ldns_pkt_free(packet);
			return LDNS_STATUS_INTERNAL_ERR;
		}
	}
	for (i = 0; i < ldns_pkt_nscount(packet); i++) {
		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
			status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
		}
		LDNS_STATUS_CHECK_GOTO(status, status_error);
		if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
			ldns_pkt_free(packet);
			return LDNS_STATUS_INTERNAL_ERR;
		}
	}
	for (i = 0; i < ldns_pkt_arcount(packet); i++) {
		status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
		if (status == LDNS_STATUS_PACKET_OVERFLOW) {
			status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
		}
		LDNS_STATUS_CHECK_GOTO(status, status_error);

		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
			ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
			ldns_write_uint32(data, ldns_rr_ttl(rr));
			ldns_pkt_set_edns_extended_rcode(packet, data[0]);
			ldns_pkt_set_edns_version(packet, data[1]);
			ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
			/* edns might not have rdfs */
			if (ldns_rr_rdf(rr, 0)) {
				ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
			}
			ldns_rr_free(rr);
			have_edns += 1;
		} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
			ldns_pkt_set_tsig(packet, rr);
			ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
		} else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
			ldns_pkt_free(packet);
			return LDNS_STATUS_INTERNAL_ERR;
		}
	}
	ldns_pkt_set_size(packet, max);
	if(have_edns)
		ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
                        - have_edns);

	*packet_p = packet;
	return status;

status_error:
	ldns_pkt_free(packet);
	return status;
}


ldns_rr_set_ttl(ldns_rr *rr, uint32_t ttl)
{
	rr->_ttl = ttl;
}


ldns_rr_list_pop_rr_list(ldns_rr_list *rr_list, size_t howmany)
{
	/* pop a number of rr's and put them in a rr_list */
	ldns_rr_list *popped;
	ldns_rr *p;
	size_t i = howmany;

	popped = ldns_rr_list_new();

	if (!popped) {
		return NULL;
	}

	while(i > 0 &&
			(p = ldns_rr_list_pop_rr(rr_list)) != NULL) {
		ldns_rr_list_push_rr(popped, p);
		i--;
	}

	if (i == howmany) { /* so i <= 0 */
		ldns_rr_list_free(popped);
		return NULL;
	} else {
		return popped;
	}
}


ldns_rdf2buffer_str_eui48(ldns_buffer *output, const ldns_rdf *rdf)
{
	if (ldns_rdf_size(rdf) != 6) {
		return LDNS_STATUS_WIRE_RDATA_ERR;
	}
	ldns_buffer_printf(output,"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
				ldns_rdf_data(rdf)[0], ldns_rdf_data(rdf)[1],
				ldns_rdf_data(rdf)[2], ldns_rdf_data(rdf)[3],
				ldns_rdf_data(rdf)[4], ldns_rdf_data(rdf)[5]);
	return ldns_buffer_status(output);
}


ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type)
{
	assert(rd != NULL);
	rd->_type = type;
}


ldns_rdf_get_type(const ldns_rdf *rd)
{
	assert(rd != NULL);
	return rd->_type;
}


ldns_pkt_algorithm2str(ldns_algorithm algorithm)
{
	char *str;
	ldns_buffer *buf;

	buf = ldns_buffer_new(10);
	if (!buf) {
		return NULL;
	}

	str = NULL;
	if (ldns_algorithm2buffer_str(buf, algorithm)
	    == LDNS_STATUS_OK) {
		str = ldns_buffer_export2str(buf);
	}

	ldns_buffer_free(buf);
	return str;
}


ldns_rr_type2buffer_str(ldns_buffer *output, const ldns_rr_type type)
{
	const ldns_rr_descriptor *descriptor;

	descriptor = ldns_rr_descript(type);

	if (descriptor && descriptor->_name) {
		ldns_buffer_printf(output, "%s", descriptor->_name);
	} else {
		/* exceptions for pseudotypes */
		switch (type) {
			case LDNS_RR_TYPE_IXFR:
				ldns_buffer_printf(output, "IXFR");
				break;
			case LDNS_RR_TYPE_AXFR:
				ldns_buffer_printf(output, "AXFR");
				break;
			case LDNS_RR_TYPE_MAILA:
				ldns_buffer_printf(output, "MAILA");
				break;
			case LDNS_RR_TYPE_MAILB:
				ldns_buffer_printf(output, "MAILB");
				break;
			case LDNS_RR_TYPE_ANY:
				ldns_buffer_printf(output, "ANY");
				break;
			default:
				ldns_buffer_printf(output, "TYPE%u", type);
		}
	}
	return ldns_buffer_status(output);
}


ldns_zone_print(FILE *output, const ldns_zone *z)
{
	ldns_zone_print_fmt(output, ldns_output_format_default, z);
}


ldns_rdf2buffer_str_tag(ldns_buffer *output, const ldns_rdf *rdf)
{
	size_t nchars;
	const uint8_t* chars;
	char ch;
	if (ldns_rdf_size(rdf) < 2) {
		return LDNS_STATUS_WIRE_RDATA_ERR;
	}
	nchars = ldns_rdf_data(rdf)[0];
	if (nchars >= ldns_rdf_size(rdf) || /* should be rdf_size - 1 */
			nchars < 1) {
		return LDNS_STATUS_WIRE_RDATA_ERR;
	}
	chars = ldns_rdf_data(rdf) + 1;
	while (nchars > 0) {
		ch = *chars++;
		if (! isalnum(ch)) {
			return LDNS_STATUS_WIRE_RDATA_ERR;
		}
		ldns_buffer_printf(output, "%c", ch);
		nchars--;
	}
	return ldns_buffer_status(output);
}


ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
                             uint32_t default_ttl, ldns_rdf *origin,
		             ldns_rdf **prev, bool question)
{
	ldns_rr *new;
	const ldns_rr_descriptor *desc;
	ldns_rr_type rr_type;
	ldns_buffer *rr_buf = NULL;
	ldns_buffer *rd_buf = NULL;
	uint32_t ttl_val;
	char  *owner = NULL;
	char  *ttl = NULL;
	ldns_rr_class clas_val;
	char  *clas = NULL;
	char  *type = NULL;
	char  *rdata = NULL;
	char  *rd = NULL;
	char  *	b64 = NULL;
	size_t rd_strlen;
	const char *delimiters;
	ssize_t c;
	ldns_rdf *owner_dname;
        const char* endptr;
        int was_unknown_rr_format = 0;
	ldns_status status = LDNS_STATUS_OK;

	/* used for types with unknown number of rdatas */
	bool done;
	bool quoted;

	ldns_rdf *r = NULL;
	uint16_t r_cnt;
	uint16_t r_min;
	uint16_t r_max;
        size_t pre_data_pos;

	new = ldns_rr_new();

	owner = LDNS_XMALLOC(char, LDNS_MAX_DOMAINLEN + 1);
	ttl = LDNS_XMALLOC(char, LDNS_TTL_DATALEN);
	clas = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN);
	rdata = LDNS_XMALLOC(char, LDNS_MAX_PACKETLEN + 1);
	rr_buf = LDNS_MALLOC(ldns_buffer);
	rd_buf = LDNS_MALLOC(ldns_buffer);
	rd = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
	b64 = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
	if (!new || !owner || !ttl || !clas || !rdata || !rr_buf || !rd_buf || !rd || !b64 ) {
		status = LDNS_STATUS_MEM_ERR;
		LDNS_FREE(rr_buf);
		goto ldnserror;
	}

	ldns_buffer_new_frm_data(rr_buf, (char*)str, strlen(str));

	/* split the rr in its parts -1 signals trouble */
	if (ldns_bget_token(rr_buf, owner, "\t\n ", LDNS_MAX_DOMAINLEN) == -1) {
		status = LDNS_STATUS_SYNTAX_ERR;
		ldns_buffer_free(rr_buf);
		goto ldnserror;
	}

	if (ldns_bget_token(rr_buf, ttl, "\t\n ", LDNS_TTL_DATALEN) == -1) {
		status = LDNS_STATUS_SYNTAX_TTL_ERR;
		ldns_buffer_free(rr_buf);
		goto ldnserror;
	}
	ttl_val = (uint32_t) ldns_str2period(ttl, &endptr);

	if (strlen(ttl) > 0 && !isdigit((int) ttl[0])) {
		/* ah, it's not there or something */
		if (default_ttl == 0) {
			ttl_val = LDNS_DEFAULT_TTL;
		} else {
			ttl_val = default_ttl;
		}
		/* we not ASSUMING the TTL is missing and that
		 * the rest of the RR is still there. That is
		 * CLASS TYPE RDATA
		 * so ttl value we read is actually the class
		 */
		clas_val = ldns_get_rr_class_by_name(ttl);
		/* class can be left out too, assume IN, current
		 * token must be type
		 */
		if (clas_val == 0) {
			clas_val = LDNS_RR_CLASS_IN;
			type = LDNS_XMALLOC(char, strlen(ttl) + 1);
			if(!type) {
				status = LDNS_STATUS_MEM_ERR;
				ldns_buffer_free(rr_buf);
				goto ldnserror;
			}
			strncpy(type, ttl, strlen(ttl) + 1);
		}
	} else {
		if (ldns_bget_token(rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) {
			status = LDNS_STATUS_SYNTAX_CLASS_ERR;
			ldns_buffer_free(rr_buf);
			goto ldnserror;
		}
		clas_val = ldns_get_rr_class_by_name(clas);
		/* class can be left out too, assume IN, current
		 * token must be type
		 */
		if (clas_val == 0) {
			clas_val = LDNS_RR_CLASS_IN;
			type = LDNS_XMALLOC(char, strlen(clas) + 1);
			if(!type) {
				status = LDNS_STATUS_MEM_ERR;
				ldns_buffer_free(rr_buf);
				goto ldnserror;
			}
			strncpy(type, clas, strlen(clas) + 1);
		}
	}
	/* the rest should still be waiting for us */

	if (!type) {
		type = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN);
		if(!type) {
			status = LDNS_STATUS_MEM_ERR;
			ldns_buffer_free(rr_buf);
			goto ldnserror;
		}
		if (ldns_bget_token(rr_buf, type, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) {
			status = LDNS_STATUS_SYNTAX_TYPE_ERR;
			ldns_buffer_free(rr_buf);
			goto ldnserror;
		}
	}

	if (ldns_bget_token(rr_buf, rdata, "\0", LDNS_MAX_PACKETLEN) == -1) {
		/* apparently we are done, and it's only a question RR
		 * so do not set status and go to ldnserror here
		*/
	}

	ldns_buffer_new_frm_data(rd_buf, rdata, strlen(rdata));

	if (strlen(owner) <= 1 && strncmp(owner, "@", 1) == 0) {
		if (origin) {
			ldns_rr_set_owner(new, ldns_rdf_clone(origin));
		} else if (prev && *prev) {
			ldns_rr_set_owner(new, ldns_rdf_clone(*prev));
		} else {
			/* default to root */
			ldns_rr_set_owner(new, ldns_dname_new_frm_str("."));
		}

		/* @ also overrides prev */
		if (prev) {
			ldns_rdf_deep_free(*prev);
			*prev = ldns_rdf_clone(ldns_rr_owner(new));
			if (!*prev) {
				status = LDNS_STATUS_MEM_ERR;
				ldns_buffer_free(rr_buf);
				goto ldnserror;
			}
		}
	} else {
		if (strlen(owner) == 0) {
			/* no ownername was given, try prev, if that fails
			 * origin, else default to root */
			if (prev && *prev) {
				ldns_rr_set_owner(new, ldns_rdf_clone(*prev));
			} else if (origin) {
				ldns_rr_set_owner(new, ldns_rdf_clone(origin));
			} else {
				ldns_rr_set_owner(new, ldns_dname_new_frm_str("."));
			}
			if(!ldns_rr_owner(new)) {
				status = LDNS_STATUS_MEM_ERR;
				ldns_buffer_free(rr_buf);
				goto ldnserror;
			}
		} else {
			owner_dname = ldns_dname_new_frm_str(owner);
			if (!owner_dname) {
				status = LDNS_STATUS_SYNTAX_ERR;
				ldns_buffer_free(rr_buf);
				goto ldnserror;
			}

			ldns_rr_set_owner(new, owner_dname);
			if (!ldns_dname_str_absolute(owner) && origin) {
				if(ldns_dname_cat(ldns_rr_owner(new),
							origin) != LDNS_STATUS_OK) {
					status = LDNS_STATUS_SYNTAX_ERR;
					ldns_buffer_free(rr_buf);
					goto ldnserror;
				}
			}
			if (prev) {
				ldns_rdf_deep_free(*prev);
				*prev = ldns_rdf_clone(ldns_rr_owner(new));
				if(!*prev) {
					status = LDNS_STATUS_MEM_ERR;
					ldns_buffer_free(rr_buf);
					goto ldnserror;
				}
			}
		}
	}
	LDNS_FREE(owner);
	owner = NULL;

	ldns_rr_set_question(new, question);

	ldns_rr_set_ttl(new, ttl_val);
	LDNS_FREE(ttl);
	ttl = NULL;

	ldns_rr_set_class(new, clas_val);
	LDNS_FREE(clas);
	clas = NULL;

	rr_type = ldns_get_rr_type_by_name(type);
	LDNS_FREE(type);
	type = NULL;

	desc = ldns_rr_descript((uint16_t)rr_type);
	ldns_rr_set_type(new, rr_type);
	if (desc) {
		/* only the rdata remains */
		r_max = ldns_rr_descriptor_maximum(desc);
		r_min = ldns_rr_descriptor_minimum(desc);
	} else {
		r_min = 0;
		r_max = 1;
	}

	/* depending on the rr_type we need to extract
	 * the rdata differently, e.g. NSEC/NSEC3 */
	switch(rr_type) {
		default:
			done = false;

			for (r_cnt = 0; !done && r_cnt < r_max; r_cnt++) {
				quoted = false;
				/* if type = B64, the field may contain spaces */
				if (ldns_rr_descriptor_field_type(desc,
					    r_cnt) == LDNS_RDF_TYPE_B64 ||
				    ldns_rr_descriptor_field_type(desc,
					    r_cnt) == LDNS_RDF_TYPE_HEX ||
				    ldns_rr_descriptor_field_type(desc,
					    r_cnt) == LDNS_RDF_TYPE_LOC ||
				    ldns_rr_descriptor_field_type(desc,
					    r_cnt) == LDNS_RDF_TYPE_WKS ||
				    ldns_rr_descriptor_field_type(desc,
					    r_cnt) == LDNS_RDF_TYPE_IPSECKEY ||
				    ldns_rr_descriptor_field_type(desc,
					    r_cnt) == LDNS_RDF_TYPE_NSEC) {
					delimiters = "\n\t";
				} else {
					delimiters = "\n\t ";
				}

				if (ldns_rdf_type_maybe_quoted(
					    ldns_rr_descriptor_field_type(
						desc, r_cnt)) &&
					    ldns_buffer_remaining(rd_buf) > 0){

					/* skip spaces */
					while (*(ldns_buffer_current(rd_buf)) == ' ') {
						ldns_buffer_skip(rd_buf, 1);
					}

					if (*(ldns_buffer_current(rd_buf)) == '\"') {
						delimiters = "\"\0";
						ldns_buffer_skip(rd_buf, 1);
						quoted = true;
					}
				}

				/* because number of fields can be variable, we can't
				   rely on _maximum() only */
				/* skip spaces */
				while (ldns_buffer_position(rd_buf) < ldns_buffer_limit(rd_buf) &&
					*(ldns_buffer_current(rd_buf)) == ' ' && !quoted
				      ) {
					ldns_buffer_skip(rd_buf, 1);
				}

				pre_data_pos = ldns_buffer_position(rd_buf);
				if ((c = ldns_bget_token(rd_buf, rd, delimiters,
							LDNS_MAX_RDFLEN)) != -1) {
					/* hmmz, rfc3597 specifies that any type can be represented with
					 * \# method, which can contain spaces...
					 * it does specify size though...
					 */
					rd_strlen = strlen(rd);

					/* unknown RR data */
					if (strncmp(rd, "\\#", 2) == 0 && !quoted && (rd_strlen == 2 || rd[2]==' ')) {
                                        	uint16_t hex_data_size;
                                                char *hex_data_str;
                                                uint16_t cur_hex_data_size;

                                                was_unknown_rr_format = 1;
                                                /* go back to before \# and skip it while setting delimiters better */
                                                ldns_buffer_set_position(rd_buf, pre_data_pos);
					        delimiters = "\n\t ";
                                                (void)ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
                                                /* read rdata octet length */
						c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
						if (c == -1) {
							/* something goes very wrong here */
                                                        LDNS_FREE(rd);
                                                        LDNS_FREE(b64);
                                                        ldns_buffer_free(rd_buf);
                                                        ldns_buffer_free(rr_buf);
                                                        LDNS_FREE(rdata);
                                                        ldns_rr_free(new);
							return LDNS_STATUS_SYNTAX_RDATA_ERR;
						}
						hex_data_size = (uint16_t) atoi(rd);
						/* copy the hex chars into hex str (which is 2 chars per byte) */
						hex_data_str = LDNS_XMALLOC(char, 2 * hex_data_size + 1);
						if (!hex_data_str) {
							/* malloc error */
                                                        LDNS_FREE(rd);
                                                        LDNS_FREE(b64);
                                                        ldns_buffer_free(rd_buf);
                                                        ldns_buffer_free(rr_buf);
                                                        LDNS_FREE(rdata);
                                                        ldns_rr_free(new);
							return LDNS_STATUS_SYNTAX_RDATA_ERR;
						}
						cur_hex_data_size = 0;
						while(cur_hex_data_size < 2 * hex_data_size) {
							c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
							if (c != -1) {
								rd_strlen = strlen(rd);
							}
							if (c == -1 || (size_t)cur_hex_data_size + rd_strlen > 2 * (size_t)hex_data_size) {
								LDNS_FREE(hex_data_str);
								LDNS_FREE(rd);
								LDNS_FREE(b64);
								ldns_buffer_free(rd_buf);
								ldns_buffer_free(rr_buf);
								LDNS_FREE(rdata);
								ldns_rr_free(new);
								return LDNS_STATUS_SYNTAX_RDATA_ERR;
							}
							strncpy(hex_data_str + cur_hex_data_size, rd, rd_strlen);
							cur_hex_data_size += rd_strlen;
						}
						hex_data_str[cur_hex_data_size] = '\0';

						/* correct the rdf type */
						/* if *we* know the type, interpret it as wireformat */
						if (desc) {
							size_t hex_pos = 0;
							uint8_t *hex_data = LDNS_XMALLOC(uint8_t, hex_data_size + 2);
                                                        ldns_status s;
                                                        if(!hex_data) {
                                                                LDNS_FREE(hex_data_str);
                                                                LDNS_FREE(rd);
                                                                LDNS_FREE(b64);
                                                                ldns_buffer_free(rd_buf);
                                                                ldns_buffer_free(rr_buf);
                                                                LDNS_FREE(rdata);
                                                                ldns_rr_free(new);
                                                                return LDNS_STATUS_MEM_ERR;
                                                        }
							ldns_write_uint16(hex_data, hex_data_size);
							ldns_hexstring_to_data(hex_data + 2, hex_data_str);
							s = ldns_wire2rdf(new, hex_data,
							                 hex_data_size+2, &hex_pos);
                                                        if(s != LDNS_STATUS_OK) {
                                                                LDNS_FREE(hex_data_str);
                                                                LDNS_FREE(rd);
                                                                LDNS_FREE(b64);
                                                                ldns_buffer_free(rd_buf);
                                                                ldns_buffer_free(rr_buf);
                                                                LDNS_FREE(rdata);
                                                                ldns_rr_free(new);
								LDNS_FREE(hex_data);
                                                                return s;
                                                        }
							LDNS_FREE(hex_data);
						} else {
							r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, hex_data_str);
                                                        if(!r) {
                                                                LDNS_FREE(hex_data_str);
                                                                LDNS_FREE(rd);
                                                                LDNS_FREE(b64);
                                                                ldns_buffer_free(rd_buf);
                                                                ldns_buffer_free(rr_buf);
                                                                LDNS_FREE(rdata);
                                                                ldns_rr_free(new);
                                                                return LDNS_STATUS_MEM_ERR;
                                                        }
							ldns_rdf_set_type(r, LDNS_RDF_TYPE_UNKNOWN);
							if(!ldns_rr_push_rdf(new, r)) {
                                                                LDNS_FREE(hex_data_str);
                                                                LDNS_FREE(rd);
                                                                LDNS_FREE(b64);
                                                                ldns_buffer_free(rd_buf);
                                                                ldns_buffer_free(rr_buf);
                                                                LDNS_FREE(rdata);
                                                                ldns_rr_free(new);
                                                                return LDNS_STATUS_MEM_ERR;
                                                        }
						}
						LDNS_FREE(hex_data_str);
					} else {
						/* Normal RR */
						switch(ldns_rr_descriptor_field_type(desc, r_cnt)) {
						case LDNS_RDF_TYPE_HEX:
						case LDNS_RDF_TYPE_B64:
							/* can have spaces, and will always be the last
							 * record of the rrdata. Read in the rest */
							if ((c = ldns_bget_token(rd_buf,
												b64,
												"\n",
												LDNS_MAX_RDFLEN))
							    != -1) {
								rd = strncat(rd,
										   b64,
										   LDNS_MAX_RDFLEN
										   - strlen(rd) - 1);
							}
							r = ldns_rdf_new_frm_str(
									ldns_rr_descriptor_field_type(desc, r_cnt),
									rd);
							break;
						case LDNS_RDF_TYPE_DNAME:
							r = ldns_rdf_new_frm_str(
									ldns_rr_descriptor_field_type(desc, r_cnt),
									rd);

							/* check if the origin should be used or concatenated */
							if (r && ldns_rdf_size(r) > 1 && ldns_rdf_data(r)[0] == 1
								&& ldns_rdf_data(r)[1] == '@') {
								ldns_rdf_deep_free(r);
								if (origin) {
									r = ldns_rdf_clone(origin);
								} else {
								     /* if this is the SOA, use its own owner name */
									if (rr_type == LDNS_RR_TYPE_SOA) {
										r = ldns_rdf_clone(ldns_rr_owner(new));
									} else {
										r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ".");
									}
								}
							} else if (r && rd_strlen >= 1 && !ldns_dname_str_absolute(rd) && origin) {
								if (ldns_dname_cat(r, origin) != LDNS_STATUS_OK) {
							                LDNS_FREE(rd);
							                LDNS_FREE(b64);
							                ldns_buffer_free(rd_buf);
							                ldns_buffer_free(rr_buf);
							                LDNS_FREE(rdata);
							                ldns_rr_free(new);
									return LDNS_STATUS_ERR;
								}
							}
							break;
						default:
							r = ldns_rdf_new_frm_str(
									ldns_rr_descriptor_field_type(desc, r_cnt),
									rd);
							break;
						}
						if (r) {
							ldns_rr_push_rdf(new, r);
						} else {
							LDNS_FREE(rd);
							LDNS_FREE(b64);
							ldns_buffer_free(rd_buf);
							ldns_buffer_free(rr_buf);
							LDNS_FREE(rdata);
							ldns_rr_free(new);
							return LDNS_STATUS_SYNTAX_RDATA_ERR;
						}
					}
					if (quoted) {
						if (ldns_buffer_available(rd_buf, 1)) {
							ldns_buffer_skip(rd_buf, 1);
						} else {
							done = true;
						}
					}
				} else {
					done = true;
				}
			}
	}
	LDNS_FREE(rd);
	LDNS_FREE(b64);
	ldns_buffer_free(rd_buf);
	ldns_buffer_free(rr_buf);
	LDNS_FREE(rdata);

	if (!question && desc && !was_unknown_rr_format && ldns_rr_rd_count(new) < r_min) {
		ldns_rr_free(new);
		return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
	}

	if (newrr) {
		*newrr = new;
	} else {
		/* Maybe the caller just wanted to see if it would parse? */
		ldns_rr_free(new);
	}
	return LDNS_STATUS_OK;

ldnserror:
	LDNS_FREE(type);
	LDNS_FREE(owner);
	LDNS_FREE(ttl);
	LDNS_FREE(clas);
	LDNS_FREE(rdata);
	LDNS_FREE(rd);
	LDNS_FREE(rd_buf);
	LDNS_FREE(b64);
	ldns_rr_free(new);
    return status;
}


ldns_rdf2buffer_str_ilnp64(ldns_buffer *output, const ldns_rdf *rdf)
{
	if (ldns_rdf_size(rdf) != 8) {
		return LDNS_STATUS_WIRE_RDATA_ERR;
	}
	ldns_buffer_printf(output,"%.4x:%.4x:%.4x:%.4x",
				ldns_read_uint16(ldns_rdf_data(rdf)),
				ldns_read_uint16(ldns_rdf_data(rdf)+2),
				ldns_read_uint16(ldns_rdf_data(rdf)+4),
				ldns_read_uint16(ldns_rdf_data(rdf)+6));
	return ldns_buffer_status(output);
}


ldns_rdf_set_size(ldns_rdf *rd, size_t size)
{
	assert(rd != NULL);
	rd->_size = size;
}


ldns_rr_list_owner(const ldns_rr_list *rr_list)
{
	if (rr_list && ldns_rr_list_rr_count(rr_list) > 0) {
		return ldns_rr_owner(ldns_rr_list_rr(rr_list, 0));
	} else {
		return NULL;
	}
}


ldns_rr_set_type(ldns_rr *rr, ldns_rr_type rr_type)
{
	rr->_rr_type = rr_type;
}


ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf)
{
	/* we could do checking (ie degrees < 90 etc)? */
	uint8_t version;
	uint8_t size;
	uint8_t horizontal_precision;
	uint8_t vertical_precision;
	uint32_t longitude;
	uint32_t latitude;
	uint32_t altitude;
	char northerness;
	char easterness;
	uint32_t h;
	uint32_t m;
	double s;

	uint32_t equator = (uint32_t) ldns_power(2, 31);

        if(ldns_rdf_size(rdf) < 1) {
                return LDNS_STATUS_WIRE_RDATA_ERR;
        }
       	version = ldns_rdf_data(rdf)[0];
	if (version == 0) {
		if(ldns_rdf_size(rdf) < 16) {
			return LDNS_STATUS_WIRE_RDATA_ERR;
		}
		size = ldns_rdf_data(rdf)[1];
		horizontal_precision = ldns_rdf_data(rdf)[2];
		vertical_precision = ldns_rdf_data(rdf)[3];

		latitude = ldns_read_uint32(&ldns_rdf_data(rdf)[4]);
		longitude = ldns_read_uint32(&ldns_rdf_data(rdf)[8]);
		altitude = ldns_read_uint32(&ldns_rdf_data(rdf)[12]);

		if (latitude > equator) {
			northerness = 'N';
			latitude = latitude - equator;
		} else {
			northerness = 'S';
			latitude = equator - latitude;
		}
		h = latitude / (1000 * 60 * 60);
		latitude = latitude % (1000 * 60 * 60);
		m = latitude / (1000 * 60);
		latitude = latitude % (1000 * 60);
		s = (double) latitude / 1000.0;
		ldns_buffer_printf(output, "%02u %02u %0.3f %c ",
			h, m, s, northerness);

		if (longitude > equator) {
			easterness = 'E';
			longitude = longitude - equator;
		} else {
			easterness = 'W';
			longitude = equator - longitude;
		}
		h = longitude / (1000 * 60 * 60);
		longitude = longitude % (1000 * 60 * 60);
		m = longitude / (1000 * 60);
		longitude = longitude % (1000 * 60);
		s = (double) longitude / (1000.0);
		ldns_buffer_printf(output, "%02u %02u %0.3f %c ",
			h, m, s, easterness);

		s = ((double) altitude) / 100;
		s -= 100000;

		if(altitude%100 != 0)
			ldns_buffer_printf(output, "%.2f", s);
		else
			ldns_buffer_printf(output, "%.0f", s);

		ldns_buffer_printf(output, "m ");

		loc_cm_print(output, (size & 0xf0) >> 4, size & 0x0f);
		ldns_buffer_printf(output, "m ");

		loc_cm_print(output, (horizontal_precision & 0xf0) >> 4,
			horizontal_precision & 0x0f);
		ldns_buffer_printf(output, "m ");

		loc_cm_print(output, (vertical_precision & 0xf0) >> 4,
			vertical_precision & 0x0f);
		ldns_buffer_printf(output, "m");

		return ldns_buffer_status(output);
	} else {
		return ldns_rdf2buffer_str_hex(output, rdf);
	}
}


ldns_rr_list_compare(const ldns_rr_list *rrl1, const ldns_rr_list *rrl2)
{
	size_t i = 0;
	int rr_cmp;

	assert(rrl1 != NULL);
	assert(rrl2 != NULL);

	for (i = 0; i < ldns_rr_list_rr_count(rrl1) && i < ldns_rr_list_rr_count(rrl2); i++) {
		rr_cmp = ldns_rr_compare(ldns_rr_list_rr(rrl1, i), ldns_rr_list_rr(rrl2, i));
		if (rr_cmp != 0) {
			return rr_cmp;
		}
	}

	if (i == ldns_rr_list_rr_count(rrl1) &&
	    i != ldns_rr_list_rr_count(rrl2)) {
		return 1;
	} else if (i == ldns_rr_list_rr_count(rrl2) &&
	           i != ldns_rr_list_rr_count(rrl1)) {
		return -1;
	} else {
		return 0;
	}
}


ldns_pktheader2buffer_str(ldns_buffer *output, const ldns_pkt *pkt)
{
	ldns_lookup_table *opcode = ldns_lookup_by_id(ldns_opcodes,
			                    (int) ldns_pkt_get_opcode(pkt));
	ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes,
			                    (int) ldns_pkt_get_rcode(pkt));

	ldns_buffer_printf(output, ";; ->>HEADER<<- ");
	if (opcode) {
		ldns_buffer_printf(output, "opcode: %s, ", opcode->name);
	} else {
		ldns_buffer_printf(output, "opcode: ?? (%u), ",
				ldns_pkt_get_opcode(pkt));
	}
	if (rcode) {
		ldns_buffer_printf(output, "rcode: %s, ", rcode->name);
	} else {
		ldns_buffer_printf(output, "rcode: ?? (%u), ", ldns_pkt_get_rcode(pkt));
	}
	ldns_buffer_printf(output, "id: %d\n", ldns_pkt_id(pkt));
	ldns_buffer_printf(output, ";; flags: ");

	if (ldns_pkt_qr(pkt)) {
		ldns_buffer_printf(output, "qr ");
	}
	if (ldns_pkt_aa(pkt)) {
		ldns_buffer_printf(output, "aa ");
	}
	if (ldns_pkt_tc(pkt)) {
		ldns_buffer_printf(output, "tc ");
	}
	if (ldns_pkt_rd(pkt)) {
		ldns_buffer_printf(output, "rd ");
	}
	if (ldns_pkt_cd(pkt)) {
		ldns_buffer_printf(output, "cd ");
	}
	if (ldns_pkt_ra(pkt)) {
		ldns_buffer_printf(output, "ra ");
	}
	if (ldns_pkt_ad(pkt)) {
		ldns_buffer_printf(output, "ad ");
	}
	ldns_buffer_printf(output, "; ");
	ldns_buffer_printf(output, "QUERY: %u, ", ldns_pkt_qdcount(pkt));
	ldns_buffer_printf(output, "ANSWER: %u, ", ldns_pkt_ancount(pkt));
	ldns_buffer_printf(output, "AUTHORITY: %u, ", ldns_pkt_nscount(pkt));
	ldns_buffer_printf(output, "ADDITIONAL: %u ", ldns_pkt_arcount(pkt));
	return ldns_buffer_status(output);
}


ldns_rr_ttl(const ldns_rr *rr)
{
	return rr->_ttl;
}


ldns_rr2canonical(ldns_rr *rr)
{
	uint16_t i;

	if (!rr) {
	  return;
        }

        ldns_dname2canonical(ldns_rr_owner(rr));

	/*
	 * lowercase the rdata dnames if the rr type is one
	 * of the list in chapter 7 of RFC3597
	 * Also added RRSIG, because a "Signer's Name" should be canonicalized
	 * too. See dnssec-bis-updates-16. We can add it to this list because
	 * the "Signer's Name"  is the only dname type rdata field in a RRSIG.
	 */
	switch(ldns_rr_get_type(rr)) {
        	case LDNS_RR_TYPE_NS:
        	case LDNS_RR_TYPE_MD:
        	case LDNS_RR_TYPE_MF:
        	case LDNS_RR_TYPE_CNAME:
        	case LDNS_RR_TYPE_SOA:
        	case LDNS_RR_TYPE_MB:
        	case LDNS_RR_TYPE_MG:
        	case LDNS_RR_TYPE_MR:
        	case LDNS_RR_TYPE_PTR:
        	case LDNS_RR_TYPE_MINFO:
        	case LDNS_RR_TYPE_MX:
        	case LDNS_RR_TYPE_RP:
        	case LDNS_RR_TYPE_AFSDB:
        	case LDNS_RR_TYPE_RT:
        	case LDNS_RR_TYPE_SIG:
        	case LDNS_RR_TYPE_PX:
        	case LDNS_RR_TYPE_NXT:
        	case LDNS_RR_TYPE_NAPTR:
        	case LDNS_RR_TYPE_KX:
        	case LDNS_RR_TYPE_SRV:
        	case LDNS_RR_TYPE_DNAME:
        	case LDNS_RR_TYPE_A6:
        	case LDNS_RR_TYPE_RRSIG:
			for (i = 0; i < ldns_rr_rd_count(rr); i++) {
				ldns_dname2canonical(ldns_rr_rdf(rr, i));
			}
			return;
		default:
			/* do nothing */
			return;
	}
}


ldns_rr_list_pop_rrset(ldns_rr_list *rr_list)
{
	ldns_rr_list *rrset;
	ldns_rr *last_rr = NULL;
	ldns_rr *next_rr;

	if (!rr_list) {
		return NULL;
	}

	rrset = ldns_rr_list_new();
	if (!last_rr) {
		last_rr = ldns_rr_list_pop_rr(rr_list);
		if (!last_rr) {
			ldns_rr_list_free(rrset);
			return NULL;
		} else {
			ldns_rr_list_push_rr(rrset, last_rr);
		}
	}

	if (ldns_rr_list_rr_count(rr_list) > 0) {
		next_rr = ldns_rr_list_rr(rr_list, ldns_rr_list_rr_count(rr_list) - 1);
	} else {
		next_rr = NULL;
	}

	while (next_rr) {
		if (
			ldns_rdf_compare(ldns_rr_owner(next_rr),
					 ldns_rr_owner(last_rr)) == 0
			&&
			ldns_rr_get_type(next_rr) == ldns_rr_get_type(last_rr)
			&&
			ldns_rr_get_class(next_rr) == ldns_rr_get_class(last_rr)
		   ) {
			ldns_rr_list_push_rr(rrset, ldns_rr_list_pop_rr(rr_list));
			if (ldns_rr_list_rr_count(rr_list) > 0) {
				last_rr = next_rr;
				next_rr = ldns_rr_list_rr(rr_list, ldns_rr_list_rr_count(rr_list) - 1);
			} else {
				next_rr = NULL;
			}
		} else {
			next_rr = NULL;
		}
	}

	return rrset;
}


ldns_rdf2buffer_str_period(ldns_buffer *output, const ldns_rdf *rdf)
{
	/* period is the number of seconds */
	if (ldns_rdf_size(rdf) != 4) {
		return LDNS_STATUS_WIRE_RDATA_ERR;
	}
	ldns_buffer_printf(output, "%u", ldns_read_uint32(ldns_rdf_data(rdf)));
	return ldns_buffer_status(output);
}


void free_xattr(stat_x *sxp)
{
	if (!sxp->xattr)
		return;
	rsync_xal_free(sxp->xattr);
	free(sxp->xattr);
	sxp->xattr = NULL;
}


static int64 xattr_lookup_hash(const item_list *xalp)
{
	const rsync_xa *rxas = xalp->items;
	size_t i;
	int64 key = hashlittle(&xalp->count, sizeof xalp->count);

	for (i = 0; i < xalp->count; i++) {
		key += hashlittle(rxas[i].name, rxas[i].name_len);
		if (rxas[i].datum_len > MAX_FULL_DATUM)
			key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN);
		else
			key += hashlittle(rxas[i].datum, rxas[i].datum_len);
	}

	if (key == 0) {
		/* This is very unlikely, but we should never
		 * return 0 as hashtable_find() doesn't like it. */
		return 1;
	}

	return key;
}


static int rsync_xal_get(const char *fname, item_list *xalp)
{
	ssize_t list_len, name_len;
	size_t datum_len, name_offset;
	char *name, *ptr;
#ifdef HAVE_LINUX_XATTRS
	int user_only = am_sender ? 0 : !am_root;
#endif
	rsync_xa *rxa;
	int count;

	/* This puts the name list into the "namebuf" buffer. */
	if ((list_len = get_xattr_names(fname)) < 0)
		return -1;

	for (name = namebuf; list_len > 0; name += name_len) {
		name_len = strlen(name) + 1;
		list_len -= name_len;

		if (saw_xattr_filter) {
			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
				continue;
		}
#ifdef HAVE_LINUX_XATTRS
		/* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
		else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
			continue;
#endif

		/* No rsync.%FOO attributes are copied w/o 2 -X options. */
		if (name_len > RPRE_LEN && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
			if ((am_sender && preserve_xattrs < 2)
			 || (am_root < 0
			  && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
			   || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
			   || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0)))
				continue;
		}

		datum_len = name_len; /* Pass extra size to get_xattr_data() */
		if (!(ptr = get_xattr_data(fname, name, &datum_len, 0)))
			return -1;

		if (datum_len > MAX_FULL_DATUM) {
			/* For large datums, we store a flag and a checksum. */
			name_offset = 1 + MAX_DIGEST_LEN;
			sum_init(-1, checksum_seed);
			sum_update(ptr, datum_len);
			free(ptr);

			if (!(ptr = new_array(char, name_offset + name_len)))
				out_of_memory("rsync_xal_get");
			*ptr = XSTATE_ABBREV;
			sum_end(ptr + 1);
		} else
			name_offset = datum_len;

		rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
		rxa->name = ptr + name_offset;
		memcpy(rxa->name, name, name_len);
		rxa->datum = ptr;
		rxa->name_len = name_len;
		rxa->datum_len = datum_len;
	}
	count = xalp->count;
	rxa = xalp->items;
	if (count > 1)
		qsort(rxa, count, sizeof (rsync_xa), rsync_xal_compare_names);
	for (rxa += count-1; count; count--, rxa--)
		rxa->num = count;
	return 0;
}


char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p)
{
	const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
	*len_p = 0; /* no extra data alloc needed from get_xattr_data() */
	return get_xattr_data(fname, name, len_p, 1);
}


static timelib_long timelib_lookup_month(char **ptr)
{
	char *word;
	char *begin = *ptr, *end;
	timelib_long  value = 0;
	const timelib_lookup_table *tp;

	while ((**ptr >= 'A' && **ptr <= 'Z') || (**ptr >= 'a' && **ptr <= 'z')) {
		++*ptr;
	}
	end = *ptr;
	word = timelib_calloc(1, end - begin + 1);
	memcpy(word, begin, end - begin);

	for (tp = timelib_month_lookup; tp->name; tp++) {
		if (strcasecmp(word, tp->name) == 0) {
			value = tp->value;
		}
	}

	timelib_free(word);
	return value;
}


static void timelib_eat_until_separator(char **ptr)
{
	++*ptr;
	while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) {
		++*ptr;
	}
}


static timelib_sll timelib_get_nr_ex(char **ptr, int max_length, int *scanned_length)
{
	char *begin, *end, *str;
	timelib_sll tmp_nr = TIMELIB_UNSET;
	int len = 0;

	while ((**ptr < '0') || (**ptr > '9')) {
		if (**ptr == '\0') {
			return TIMELIB_UNSET;
		}
		++*ptr;
	}
	begin = *ptr;
	while ((**ptr >= '0') && (**ptr <= '9') && len < max_length) {
		++*ptr;
		++len;
	}
	end = *ptr;
	if (scanned_length) {
		*scanned_length = end - begin;
	}
	str = timelib_calloc(1, end - begin + 1);
	memcpy(str, begin, end - begin);
	tmp_nr = strtoll(str, NULL, 10);
	timelib_free(str);
	return tmp_nr;
}


const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void)
{
	return timelib_timezone_lookup;
}


static const timelib_relunit* timelib_lookup_relunit(char **ptr)
{
	char *word;
	char *begin = *ptr, *end;
	const timelib_relunit *tp, *value = NULL;

	while (**ptr != '\0' && **ptr != ' ' && **ptr != ',' && **ptr != '\t' && **ptr != ';' && **ptr != ':' &&
           **ptr != '/' && **ptr != '.' && **ptr != '-' && **ptr != '(' && **ptr != ')' ) {
		++*ptr;
	}
	end = *ptr;
	word = timelib_calloc(1, end - begin + 1);
	memcpy(word, begin, end - begin);

	for (tp = timelib_relunit_lookup; tp->name; tp++) {
		if (strcasecmp(word, tp->name) == 0) {
			value = tp;
			break;
		}
	}

	timelib_free(word);
	return value;
}


static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len,
					 char __user *optval, int __user *optlen)
{
	sctp_peeloff_flags_arg_t peeloff;
	struct file *newfile = NULL;
	int retval = 0;

	if (len < sizeof(sctp_peeloff_flags_arg_t))
		return -EINVAL;
	len = sizeof(sctp_peeloff_flags_arg_t);
	if (copy_from_user(&peeloff, optval, len))
		return -EFAULT;

	retval = sctp_getsockopt_peeloff_common(sk, &peeloff.p_arg,
						&newfile, peeloff.flags);
	if (retval < 0)
		goto out;

	/* Return the fd mapped to the new socket.  */
	if (put_user(len, optlen)) {
		fput(newfile);
		put_unused_fd(retval);
		return -EFAULT;
	}

	if (copy_to_user(optval, &peeloff, len)) {
		fput(newfile);
		put_unused_fd(retval);
		return -EFAULT;
	}
	fd_install(retval, newfile);
out:
	return retval;
}


	static void appendNullTerminatedKeyValue(string &output, const StaticString &key,
		const StaticString &value)
	{
		output.append(key.data(), key.size());
		output.append(1, '\0');
		output.append(value.data(), value.size());
		output.append(1, '\0');
	}


int seccomp_filter_set_add(Hashmap *filter, bool add, const SyscallFilterSet *set) {
        const char *i;
        int r;

        assert(set);

        NULSTR_FOREACH(i, set->value) {

                if (i[0] == '@') {
                        const SyscallFilterSet *more;

                        more = syscall_filter_set_find(i);
                        if (!more)
                                return -ENXIO;

                        r = seccomp_filter_set_add(filter, add, more);
                        if (r < 0)
                                return r;
                } else {
                        int id;

                        id = seccomp_syscall_resolve_name(i);
                        if (id == __NR_SCMP_ERROR) {
                                log_debug("Couldn't resolve system call, ignoring: %s", i);
                                continue;
                        }

                        if (add) {
                                r = hashmap_put(filter, INT_TO_PTR(id + 1), INT_TO_PTR(-1));
                                if (r < 0)
                                        return r;
                        } else
                                (void) hashmap_remove(filter, INT_TO_PTR(id + 1));
                }
        }

        return 0;
}