int imap_open_connection(struct ImapAccountData *adata)
{
  if (mutt_socket_open(adata->conn) < 0)
    return -1;

  adata->state = IMAP_CONNECTED;

  if (imap_cmd_step(adata) != IMAP_RES_OK)
  {
    imap_close_connection(adata);
    return -1;
  }

  if (mutt_str_startswith(adata->buf, "* OK", CASE_IGNORE))
  {
    if (!mutt_str_startswith(adata->buf, "* OK [CAPABILITY", CASE_IGNORE) &&
        check_capabilities(adata))
    {
      goto bail;
    }
#ifdef USE_SSL
    /* Attempt STARTTLS if available and desired. */
    if (!adata->conn->ssf && (C_SslForceTls || (adata->capabilities & IMAP_CAP_STARTTLS)))
    {
      enum QuadOption ans;

      if (C_SslForceTls)
        ans = MUTT_YES;
      else if ((ans = query_quadoption(C_SslStarttls,
                                       _("Secure connection with TLS?"))) == MUTT_ABORT)
      {
        goto err_close_conn;
      }
      if (ans == MUTT_YES)
      {
        enum ImapExecResult rc = imap_exec(adata, "STARTTLS", IMAP_CMD_SINGLE);
        // Clear any data after the STARTTLS acknowledgement
        mutt_socket_empty(adata->conn);

        if (rc == IMAP_EXEC_FATAL)
          goto bail;
        if (rc != IMAP_EXEC_ERROR)
        {
          if (mutt_ssl_starttls(adata->conn))
          {
            mutt_error(_("Could not negotiate TLS connection"));
            goto err_close_conn;
          }
          else
          {
            /* RFC2595 demands we recheck CAPABILITY after TLS completes. */
            if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NO_FLAGS))
              goto bail;
          }
        }
      }
    }

    if (C_SslForceTls && !adata->conn->ssf)
    {
      mutt_error(_("Encrypted connection unavailable"));
      goto err_close_conn;
    }
#endif
  }
  else if (mutt_str_startswith(adata->buf, "* PREAUTH", CASE_IGNORE))
  {
#ifdef USE_SSL
    /* An unencrypted PREAUTH response is most likely a MITM attack.
     * Require a confirmation. */
    if (adata->conn->ssf == 0)
    {
      bool proceed = true;
      if (C_SslForceTls)
      {
        proceed = false;
      }
      else if (C_SslStarttls != MUTT_NO)
      {
        proceed = mutt_yesorno(_("Abort unencrypted PREAUTH connection?"),
                               C_SslStarttls) != MUTT_NO;
      }
      if (!proceed)
      {
        mutt_error(_("Encrypted connection unavailable"));
        goto err_close_conn;
      }
    }
#endif

    adata->state = IMAP_AUTHENTICATED;
    if (check_capabilities(adata) != 0)
      goto bail;
    FREE(&adata->capstr);
  }
  else
  {
    imap_error("imap_open_connection()", adata->buf);
    goto bail;
  }

  return 0;

#ifdef USE_SSL
err_close_conn:
  imap_close_connection(adata);
#endif
bail:
  FREE(&adata->capstr);
  return -1;
}


int pop_reconnect(struct Mailbox *m)
{
  struct PopAccountData *adata = pop_adata_get(m);

  if (adata->status == POP_CONNECTED)
    return 0;

  while (true)
  {
    mutt_socket_close(adata->conn);

    int ret = pop_open_connection(adata);
    if (ret == 0)
    {
      struct Progress progress;
      mutt_progress_init(&progress, _("Verifying message indexes..."), MUTT_PROGRESS_NET, 0);

      for (int i = 0; i < m->msg_count; i++)
      {
        struct PopEmailData *edata = pop_edata_get(m->emails[i]);
        edata->refno = -1;
      }

      ret = pop_fetch_data(adata, "UIDL\r\n", &progress, check_uidl, m);
      if (ret == -2)
      {
        mutt_error("%s", adata->err_msg);
      }
    }
    if (ret == 0)
      return 0;

    pop_logout(m);

    if (ret < -1)
      return -1;

    if (query_quadoption(C_PopReconnect,
                         _("Connection lost. Reconnect to POP server?")) != MUTT_YES)
    {
      return -1;
    }
  }
}


int imap_complete(char *buf, size_t buflen, const char *path)
{
  struct ImapAccountData *adata = NULL;
  struct ImapMboxData *mdata = NULL;
  char tmp[2048];
  struct ImapList listresp = { 0 };
  char completion[1024];
  int clen;
  size_t matchlen = 0;
  int completions = 0;
  int rc;

  if (imap_adata_find(path, &adata, &mdata) < 0)
  {
    mutt_str_strfcpy(buf, path, buflen);
    return complete_hosts(buf, buflen);
  }

  /* fire off command */
  snprintf(tmp, sizeof(tmp), "%s \"\" \"%s%%\"",
           C_ImapListSubscribed ? "LSUB" : "LIST", mdata->real_name);

  imap_cmd_start(adata, tmp);

  /* and see what the results are */
  mutt_str_strfcpy(completion, mdata->name, sizeof(completion));
  imap_mdata_free((void *) &mdata);

  adata->cmdresult = &listresp;
  do
  {
    listresp.name = NULL;
    rc = imap_cmd_step(adata);

    if ((rc == IMAP_RES_CONTINUE) && listresp.name)
    {
      /* if the folder isn't selectable, append delimiter to force browse
       * to enter it on second tab. */
      if (listresp.noselect)
      {
        clen = strlen(listresp.name);
        listresp.name[clen++] = listresp.delim;
        listresp.name[clen] = '\0';
      }
      /* copy in first word */
      if (!completions)
      {
        mutt_str_strfcpy(completion, listresp.name, sizeof(completion));
        matchlen = strlen(completion);
        completions++;
        continue;
      }

      matchlen = longest_common_prefix(completion, listresp.name, 0, matchlen);
      completions++;
    }
  } while (rc == IMAP_RES_CONTINUE);
  adata->cmdresult = NULL;

  if (completions)
  {
    /* reformat output */
    imap_qualify_path(buf, buflen, &adata->conn->account, completion);
    mutt_pretty_mailbox(buf, buflen);
    return 0;
  }

  return -1;
}


static int cmd_status(const char *s)
{
  s = imap_next_word((char *) s);

  if (mutt_str_startswith(s, "OK", CASE_IGNORE))
    return IMAP_RES_OK;
  if (mutt_str_startswith(s, "NO", CASE_IGNORE))
    return IMAP_RES_NO;

  return IMAP_RES_BAD;
}


static int go7007_snd_free(struct snd_device *device)
{
	struct go7007 *go = device->device_data;

	kfree(go->snd_context);
	go->snd_context = NULL;
	return 0;
}


DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
{
	int ph, nc, retval=0;

	if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
		_throw("tjPlaneHeight(): Invalid argument");
	nc=(subsamp==TJSAMP_GRAY? 1:3);
	if(componentID<0 || componentID>=nc)
		_throw("tjPlaneHeight(): Invalid argument");

	ph=PAD(height, tjMCUHeight[subsamp]/8);
	if(componentID==0)
		retval=ph;
	else
		retval=ph*8/tjMCUHeight[subsamp];

	bailout:
	return retval;
}


DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
	const unsigned char *srcBuf, int width, int pitch, int height,
	int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)
{
	unsigned char *dstPlanes[3];
	int pw0, ph0, strides[3], retval=-1;

	if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
		|| subsamp<0 || subsamp>=NUMSUBOPT)
		_throw("tjEncodeYUV3(): Invalid argument");

	pw0=tjPlaneWidth(0, width, subsamp);
	ph0=tjPlaneHeight(0, height, subsamp);
	dstPlanes[0]=dstBuf;
	strides[0]=PAD(pw0, pad);
	if(subsamp==TJSAMP_GRAY)
	{
		strides[1]=strides[2]=0;
		dstPlanes[1]=dstPlanes[2]=NULL;
	}
	else
	{
		int pw1=tjPlaneWidth(1, width, subsamp);
		int ph1=tjPlaneHeight(1, height, subsamp);
		strides[1]=strides[2]=PAD(pw1, pad);
		dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
		dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
	}

	return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
		dstPlanes, strides, subsamp, flags);

	bailout:
	return retval;
}


static int getSubsamp(j_decompress_ptr dinfo)
{
	int retval=-1, i, k;

	/* The sampling factors actually have no meaning with grayscale JPEG files,
	   and in fact it's possible to generate grayscale JPEGs with sampling
	   factors > 1 (even though those sampling factors are ignored by the
	   decompressor.)  Thus, we need to treat grayscale as a special case. */
	if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE)
		return TJSAMP_GRAY;

	for(i=0; i<NUMSUBOPT; i++)
	{
		if(dinfo->num_components==pixelsize[i]
			|| ((dinfo->jpeg_color_space==JCS_YCCK
				|| dinfo->jpeg_color_space==JCS_CMYK)
					&& pixelsize[i]==3 && dinfo->num_components==4))
		{
			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
			{
				int match=0;
				for(k=1; k<dinfo->num_components; k++)
				{
					int href=1, vref=1;
					if((dinfo->jpeg_color_space==JCS_YCCK
						|| dinfo->jpeg_color_space==JCS_CMYK) && k==3)
					{
						href=tjMCUWidth[i]/8;  vref=tjMCUHeight[i]/8;
					}
					if(dinfo->comp_info[k].h_samp_factor==href
						&& dinfo->comp_info[k].v_samp_factor==vref)
						match++;
				}
				if(match==dinfo->num_components-1)
				{
					retval=i;  break;
				}
			}
			/* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
			   in non-standard ways. */
			if(dinfo->comp_info[0].h_samp_factor==2 &&
				dinfo->comp_info[0].v_samp_factor==2 &&
				(i==TJSAMP_422 || i==TJSAMP_440))
			{
				int match=0;
				for(k=1; k<dinfo->num_components; k++)
				{
					int href=tjMCUHeight[i]/8, vref=tjMCUWidth[i]/8;
					if((dinfo->jpeg_color_space==JCS_YCCK
						|| dinfo->jpeg_color_space==JCS_CMYK) && k==3)
					{
						href=vref=2;
					}
					if(dinfo->comp_info[k].h_samp_factor==href
						&& dinfo->comp_info[k].v_samp_factor==vref)
						match++;
				}
				if(match==dinfo->num_components-1)
				{
					retval=i;  break;
				}
			}
			/* Handle 4:4:4 images whose sampling factors are specified in
			   non-standard ways. */
			if(dinfo->comp_info[0].h_samp_factor*dinfo->comp_info[0].v_samp_factor<=
				D_MAX_BLOCKS_IN_MCU/pixelsize[i] && i==TJSAMP_444)
			{
				int match=0;
				for(k=1; k<dinfo->num_components; k++) {
					if(dinfo->comp_info[i].h_samp_factor==
						dinfo->comp_info[0].h_samp_factor &&
						dinfo->comp_info[i].v_samp_factor==
						dinfo->comp_info[0].v_samp_factor)
						match++;
					if(match==dinfo->num_components-1)
					{
						retval=i;  break;
					}
				}
			}
		}
	}
	return retval;
}


Guint FoFiTrueType::charToTag(const char *tagName)
{
  int n = strlen(tagName);
  Guint tag = 0;
  int i;

  if (n > 4) n = 4;
  for (i = 0;i < n;i++) {
    tag <<= 8;
    tag |= tagName[i] & 0xff;
  }
  for (;i < 4;i++) {
    tag <<= 8;
    tag |= ' ';
  }
  return tag;
}


FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA):
  FoFiBase(fileA, lenA, freeFileDataA)
{
  tables = NULL;
  nTables = 0;
  cmaps = NULL;
  nCmaps = 0;
  nameToGID = NULL;
  parsedOk = gFalse;
  faceIndex = faceIndexA;
  gsubFeatureTable = 0;
  gsubLookupList = 0;

  parse();
}


snmp_synch_response_cb(netsnmp_session * ss,
                       netsnmp_pdu *pdu,
                       netsnmp_pdu **response, snmp_callback pcb)
{
    struct synch_state    lstate, *state;
    snmp_callback         cbsav;
    void                 *cbmagsav;
    int                   numfds, count;
    netsnmp_large_fd_set  fdset;
    struct timeval        timeout, *tvp;
    int                   block;

    memset((void *) &lstate, 0, sizeof(lstate));
    state = &lstate;
    cbsav = ss->callback;
    cbmagsav = ss->callback_magic;
    ss->callback = pcb;
    ss->callback_magic = (void *) state;
    netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);

    if (snmp_send(ss, pdu) == 0) {
        snmp_free_pdu(pdu);
        state->status = STAT_ERROR;
    } else {
        state->reqid = pdu->reqid;
        state->waiting = 1;
    }

    while (state->waiting) {
        numfds = 0;
        NETSNMP_LARGE_FD_ZERO(&fdset);
        block = NETSNMP_SNMPBLOCK;
        tvp = &timeout;
        timerclear(tvp);
        snmp_sess_select_info2_flags(NULL, &numfds, &fdset, tvp, &block,
                                     NETSNMP_SELECT_NOALARMS);
        if (block == 1)
            tvp = NULL;         /* block without timeout */
        count = netsnmp_large_fd_set_select(numfds, &fdset, NULL, NULL, tvp);
        if (count > 0) {
            snmp_read2(&fdset);
        } else {
            switch (count) {
            case 0:
                snmp_timeout();
                break;
            case -1:
                if (errno == EINTR) {
                    continue;
                } else {
                    snmp_errno = SNMPERR_GENERR;    /*MTCRITICAL_RESOURCE */
                    /*
                     * CAUTION! if another thread closed the socket(s)
                     * waited on here, the session structure was freed.
                     * It would be nice, but we can't rely on the pointer.
                     * ss->s_snmp_errno = SNMPERR_GENERR;
                     * ss->s_errno = errno;
                     */
                    snmp_set_detail(strerror(errno));
                }
                /* FALLTHRU */
            default:
                state->status = STAT_ERROR;
                state->waiting = 0;
            }
        }

        if ( ss->flags & SNMP_FLAGS_RESP_CALLBACK ) {
            void (*cb)(void);
            cb = (void (*)(void))(ss->myvoid);
            cb();        /* Used to invoke 'netsnmp_check_outstanding_agent_requests();'
                            on internal AgentX queries.  */
        }
    }
    *response = state->pdu;
    ss->callback = cbsav;
    ss->callback_magic = cbmagsav;
    netsnmp_large_fd_set_cleanup(&fdset);
    return state->status;
}


snmp_set_var_typed_integer(netsnmp_variable_list * newvar,
                           u_char type, long val)
{
    newvar->type = type;
    return snmp_set_var_value(newvar, &val, sizeof(long));
}


snmp_errstring(int errstat)
{
    const char * const error_string[19] = {
        "(noError) No Error",
        "(tooBig) Response message would have been too large.",
        "(noSuchName) There is no such variable name in this MIB.",
        "(badValue) The value given has the wrong type or length.",
        "(readOnly) The two parties used do not have access to use the specified SNMP PDU.",
        "(genError) A general failure occured",
        "noAccess",
        "wrongType (The set datatype does not match the data type the agent expects)",
        "wrongLength (The set value has an illegal length from what the agent expects)",
        "wrongEncoding",
        "wrongValue (The set value is illegal or unsupported in some way)",
        "noCreation (That table does not support row creation or that object can not ever be created)",
        "inconsistentValue (The set value is illegal or unsupported in some way)",
        "resourceUnavailable (This is likely a out-of-memory failure within the agent)",
        "commitFailed",
        "undoFailed",
        "authorizationError (access denied to that object)",
        "notWritable (That object does not support modification)",
        "inconsistentName (That object can not currently be created)"
    };

    if (errstat <= MAX_SNMP_ERR && errstat >= SNMP_ERR_NOERROR) {
        return error_string[errstat];
    } else {
        return "Unknown Error";
    }
}


snmp_clone_mem(void **dstPtr, const void *srcPtr, unsigned len)
{
    *dstPtr = NULL;
    if (srcPtr) {
        *dstPtr = malloc(len + 1);
        if (!*dstPtr) {
            return 1;
        }
        memmove(*dstPtr, srcPtr, len);
        /*
         * this is for those routines that expect 0-terminated strings!!!
         * someone should rather have called strdup
         */
        ((char *) *dstPtr)[len] = 0;
    }
    return 0;
}


usm_lookup_auth_type(const char *str)
{
    return usm_lookup_alg_type(str, usm_auth_type );
}


usm_add_user_to_list(struct usmUser *user, struct usmUser *puserList)
{
    struct usmUser *nptr, *pptr, *optr;

    /*
     * loop through puserList till we find the proper, sorted place to
     * insert the new user
     */
    /* XXX - how to handle a NULL user->name ?? */
    /* XXX - similarly for a NULL nptr->name ?? */
    for (nptr = puserList, pptr = NULL; nptr != NULL;
         pptr = nptr, nptr = nptr->next) {
        if (nptr->engineIDLen > user->engineIDLen)
            break;

        if (user->engineID == NULL && nptr->engineID != NULL)
            break;

        if (nptr->engineIDLen == user->engineIDLen &&
            (nptr->engineID != NULL && user->engineID != NULL &&
             memcmp(nptr->engineID, user->engineID,
                    user->engineIDLen) > 0))
            break;

        if (!(nptr->engineID == NULL && user->engineID != NULL)) {
            if (nptr->engineIDLen == user->engineIDLen &&
                ((nptr->engineID == NULL && user->engineID == NULL) ||
                 memcmp(nptr->engineID, user->engineID,
                        user->engineIDLen) == 0)
                && strlen(nptr->name) > strlen(user->name))
                break;

            if (nptr->engineIDLen == user->engineIDLen &&
                ((nptr->engineID == NULL && user->engineID == NULL) ||
                 memcmp(nptr->engineID, user->engineID,
                        user->engineIDLen) == 0)
                && strlen(nptr->name) == strlen(user->name)
                && strcmp(nptr->name, user->name) > 0)
                break;

            if (nptr->engineIDLen == user->engineIDLen &&
                ((nptr->engineID == NULL && user->engineID == NULL) ||
                 memcmp(nptr->engineID, user->engineID,
                        user->engineIDLen) == 0)
                && strlen(nptr->name) == strlen(user->name)
                && strcmp(nptr->name, user->name) == 0) {
                /*
                 * the user is an exact match of a previous entry.
                 * Credentials may be different, though, so remove
                 * the old entry (and add the new one)!
                 */
                if (pptr) { /* change prev's next pointer */
                  pptr->next = nptr->next;
                }
                if (nptr->next) { /* change next's prev pointer */
                  nptr->next->prev = pptr;
                }
                optr = nptr;
                nptr = optr->next; /* add new user at this position */
                /* free the old user */
                optr->next=NULL;
                optr->prev=NULL;
                usm_free_user(optr);
                break; /* new user will be added below */
            }
        }
    }

    /*
     * nptr should now point to the user that we need to add ourselves
     * in front of, and pptr should be our new 'prev'.
     */

    /*
     * change our pointers
     */
    user->prev = pptr;
    user->next = nptr;

    /*
     * change the next's prev pointer
     */
    if (user->next)
        user->next->prev = user;

    /*
     * change the prev's next pointer
     */
    if (user->prev)
        user->prev->next = user;

    /*
     * rewind to the head of the list and return it (since the new head
     * could be us, we need to notify the above routine who the head now is.
     */
    for (pptr = user; pptr->prev != NULL; pptr = pptr->prev);
    return pptr;
}


snmp_clone_pdu(netsnmp_pdu *pdu)
{
    return _clone_pdu(pdu, 0);  /* copies all variables */
}


snmp_reset_var_buffers(netsnmp_variable_list * var)
{
    while (var) {
        if (var->name != var->name_loc) {
            if(NULL != var->name)
                free(var->name);
            var->name = var->name_loc;
            var->name_length = 0;
        }
        if (var->val.string != var->buf) {
            if (NULL != var->val.string)
                free(var->val.string);
            var->val.string = var->buf;
            var->val_len = 0;
        }
        var = var->next_variable;
    }
}


_row_status_state_all_values_createAndGo(netsnmp_state_machine_input *input,
                                         netsnmp_state_machine_step *step)
{
    rowcreate_state       *ctx;
    netsnmp_variable_list *vars, *rs_var;
    int                    rc;

    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
    netsnmp_require_ptr_LRV( step, SNMPERR_GENERR );
    netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR );

    ctx = (rowcreate_state *)input->input_context;

    DEBUGMSGT(("row_create:called", "called %s\n", step->name));

    vars = snmp_clone_varbind(ctx->vars);
    netsnmp_require_ptr_LRV(vars, SNMPERR_GENERR);

    /*
     * make sure row stats is createAndGo
     */
    rs_var = _get_vb_num(vars, ctx->row_status_index + 1);
    if (NULL == rs_var) {
        snmp_free_varbind(vars);
        return SNMPERR_GENERR;
    }

    if (*rs_var->val.integer != RS_CREATEANDGO)
        *rs_var->val.integer = RS_CREATEANDGO;

    /*
     * send set
     */
    rc = netsnmp_query_set( vars, ctx->session );
    if (-2 == rc)
        rc = SNMPERR_ABORT;

    snmp_free_varbind(vars);

    return rc;
}


init_usm(void)
{
    struct snmp_secmod_def *def;
    char *type;

    DEBUGMSGTL(("init_usm", "unit_usm: %" NETSNMP_PRIo "u %" NETSNMP_PRIo "u\n",
                usmNoPrivProtocol[0], usmNoPrivProtocol[1]));

    sc_init();                  /* initalize scapi code */

    /*
     * register ourselves as a security service
     */
    def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
    if (def == NULL)
        return;
    /*
     * XXX: def->init_sess_secmod move stuff from snmp_api.c
     */
    def->encode_reverse = usm_secmod_rgenerate_out_msg;
    def->encode_forward = usm_secmod_generate_out_msg;
    def->decode = usm_secmod_process_in_msg;
    def->pdu_clone = usm_clone;
    def->pdu_free_state_ref = usm_free_usmStateReference;
    def->session_setup = usm_session_init;
    def->handle_report = usm_handle_report;
    def->probe_engineid = usm_discover_engineid;
    def->post_probe_engineid = usm_create_user_from_session_hook;
    if (register_sec_mod(USM_SEC_MODEL_NUMBER, "usm", def) != SNMPERR_SUCCESS) {
        SNMP_FREE(def);
        snmp_log(LOG_ERR, "could not register usm sec mod\n");
        return;
    }

    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
                           SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
                           init_usm_post_config, NULL);

    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
                           SNMP_CALLBACK_SHUTDOWN,
                           deinit_usm_post_config, NULL);

    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
                           SNMP_CALLBACK_SHUTDOWN,
                           free_engineID, NULL);

    register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf,
                            NULL, "MD5|SHA|SHA-512|SHA-384|SHA-256|SHA-224");
    register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
                            NULL,
                            "DES"
#ifdef HAVE_AES
                            "|AES|AES-128"
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
                            "|AES-192|AES-256"
#endif /* NETSNMP_DRAFT_BLUMENTHAL_AES_04 */
#else
                            " (AES support not available)"
#endif
                           );

    /*
     * Free stuff at shutdown time
     */
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
                           SNMP_CALLBACK_SHUTDOWN,
                           free_enginetime_on_shutdown, NULL);

    type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE);

    register_config_handler(type, "userSetAuthPass", usm_set_password,
                            NULL, NULL);
    register_config_handler(type, "userSetPrivPass", usm_set_password,
                            NULL, NULL);
    register_config_handler(type, "userSetAuthKey", usm_set_password, NULL,
                            NULL);
    register_config_handler(type, "userSetPrivKey", usm_set_password, NULL,
                            NULL);
    register_config_handler(type, "userSetAuthLocalKey", usm_set_password,
                            NULL, NULL);
    register_config_handler(type, "userSetPrivLocalKey", usm_set_password,
                            NULL, NULL);
}


_PUBLIC_ NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
			     struct socket_address *dest,
			     struct nbt_name_packet *request)
{
	struct nbt_name_request *req;
	enum ndr_err_code ndr_err;

	req = talloc_zero(nbtsock, struct nbt_name_request);
	NT_STATUS_HAVE_NO_MEMORY(req);

	req->nbtsock   = nbtsock;
	req->dest = socket_address_copy(req, dest);
	if (req->dest == NULL) goto failed;
	req->state     = NBT_REQUEST_SEND;
	req->is_reply = true;

	talloc_set_destructor(req, nbt_name_request_destructor);

	if (DEBUGLVL(10)) {
		NDR_PRINT_DEBUG(nbt_name_packet, request);
	}

	ndr_err = ndr_push_struct_blob(&req->encoded, req,
				       request,
				       (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		talloc_free(req);
		return ndr_map_error2ntstatus(ndr_err);
	}

	DLIST_ADD_END(nbtsock->send_queue, req);

	TEVENT_FD_WRITEABLE(nbtsock->fde);

	return NT_STATUS_OK;

failed:
	talloc_free(req);
	return NT_STATUS_NO_MEMORY;
}


str_to_uid(pam_handle_t *pamh, const char *value, uid_t default_value, const char *param) {
    unsigned long ul;
    char *ep;
    uid_t uid;

    errno = 0;
    ul = strtoul(value, &ep, 10);
    if (!(ul >= MAX_UID_VALUE
        || (uid_t)ul >= MAX_UID_VALUE
        || (errno != 0 && ul == 0)
        || value == ep
        || *ep != '\0')) {
        uid = (uid_t)ul;
    } else {
        pam_syslog(pamh, LOG_ERR, "Parameter \"%s=%s\" invalid, "
                   "setting to %u", param, value, default_value);
        uid = default_value;
    }

    return uid;
}


static void aarp_expire_timeout(struct timer_list *unused)
{
	int ct;

	write_lock_bh(&aarp_lock);

	for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
		__aarp_expire_timer(&resolved[ct]);
		__aarp_kick(&unresolved[ct]);
		__aarp_expire_timer(&unresolved[ct]);
		__aarp_expire_timer(&proxies[ct]);
	}

	write_unlock_bh(&aarp_lock);
	mod_timer(&aarp_timer, jiffies +
			       (unresolved_count ? sysctl_aarp_tick_time :
				sysctl_aarp_expiry_time));
}


static struct aarp_entry *aarp_alloc(void)
{
	struct aarp_entry *a = kmalloc(sizeof(*a), GFP_ATOMIC);

	if (a)
		skb_queue_head_init(&a->packet_queue);
	return a;
}


	__acquires(aarp_lock)
{
	struct aarp_iter_state *iter = seq->private;

	read_lock_bh(&aarp_lock);
	iter->table     = resolved;
	iter->bucket    = 0;

	return *pos ? iter_next(iter, pos) : SEQ_START_TOKEN;
}


ModuleExport size_t RegisterXPMImage(void)
{
  MagickInfo
    *entry;

  if (xpm_symbolic == (SplayTreeInfo *) NULL)
    xpm_symbolic=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
      RelinquishMagickMemory);
  entry=SetMagickInfo("PICON");
  entry->decoder=(DecodeImageHandler *) ReadXPMImage;
  entry->encoder=(EncodeImageHandler *) WritePICONImage;
  entry->adjoin=MagickFalse;
  entry->description=ConstantString("Personal Icon");
  entry->magick_module=ConstantString("XPM");
  (void) RegisterMagickInfo(entry);
  entry=SetMagickInfo("PM");
  entry->decoder=(DecodeImageHandler *) ReadXPMImage;
  entry->encoder=(EncodeImageHandler *) WriteXPMImage;
  entry->adjoin=MagickFalse;
  entry->stealth=MagickTrue;
  entry->description=ConstantString("X Windows system pixmap (color)");
  entry->magick_module=ConstantString("XPM");
  (void) RegisterMagickInfo(entry);
  entry=SetMagickInfo("XPM");
  entry->decoder=(DecodeImageHandler *) ReadXPMImage;
  entry->encoder=(EncodeImageHandler *) WriteXPMImage;
  entry->magick=(IsImageFormatHandler *) IsXPM;
  entry->adjoin=MagickFalse;
  entry->description=ConstantString("X Windows system pixmap (color)");
  entry->magick_module=ConstantString("XPM");
  (void) RegisterMagickInfo(entry);
  return(MagickImageCoderSignature);
}


webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst)
{
    return ((ws_ctx_t *)cl->wsctx)->encode(cl, src, len, dst);
}


webSocketsDecode(rfbClientPtr cl, char *dst, int len)
{
    return ((ws_ctx_t *)cl->wsctx)->decode(cl, dst, len);
}


webSocketCheckDisconnect(rfbClientPtr cl)
{
    ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
    /* With Base64 encoding we need at least 4 bytes */
    char peekbuf[4];
    int n;

    if (wsctx->version == WEBSOCKETS_VERSION_HYBI)
	return FALSE;

    if (cl->sslctx)
	n = rfbssl_peek(cl, peekbuf, 4);
    else
	n = recv(cl->sock, peekbuf, 4, MSG_PEEK);

    if (n <= 0) {
	if (n != 0)
	    rfbErr("%s: peek; %m", __func__);
	rfbCloseClient(cl);
	return TRUE;
    }

    if (peekbuf[0] == '\xff') {
	int doclose = 0;
	/* Make sure we don't miss a client disconnect on an end frame
	 * marker. Because we use a peek buffer in some cases it is not
	 * applicable to wait for more data per select(). */
	switch (n) {
	    case 3:
		if (peekbuf[1] == '\xff' && peekbuf[2] == '\x00')
		    doclose = 1;
		break;
	    case 2:
		if (peekbuf[1] == '\x00')
		    doclose = 1;
		break;
	    default:
		return FALSE;
	}

	if (cl->sslctx)
	    n = rfbssl_read(cl, peekbuf, n);
	else
	    n = read(cl->sock, peekbuf, n);

	if (doclose) {
	    rfbErr("%s: websocket close frame received\n", __func__);
	    rfbCloseClient(cl);
	}
	return TRUE;
    }
    return FALSE;
}


exif_entry_format_value(ExifEntry *e, char *val, size_t maxlen)
{
	ExifByte v_byte;
	ExifShort v_short;
	ExifSShort v_sshort;
	ExifLong v_long;
	ExifRational v_rat;
	ExifSRational v_srat;
	ExifSLong v_slong;
	unsigned int i;
	size_t len;
	const ExifByteOrder o = exif_data_get_byte_order (e->parent->parent);

	if (!e->size || !maxlen)
		return;
	switch (e->format) {
	case EXIF_FORMAT_UNDEFINED:
		snprintf (val, maxlen, _("%i bytes undefined data"), e->size);
		break;
	case EXIF_FORMAT_BYTE:
	case EXIF_FORMAT_SBYTE:
		v_byte = e->data[0];
		snprintf (val, maxlen, "0x%02x", v_byte);
		len = strlen (val);
		for (i = 1; i < e->components; i++) {
			v_byte = e->data[i];
			snprintf (val+len, maxlen-len, ", 0x%02x", v_byte);
			len += strlen (val+len);
			if (len >= maxlen-1) break;
		}
		break;
	case EXIF_FORMAT_SHORT:
		v_short = exif_get_short (e->data, o);
		snprintf (val, maxlen, "%u", v_short);
		len = strlen (val);
		for (i = 1; i < e->components; i++) {
			v_short = exif_get_short (e->data +
				exif_format_get_size (e->format) * i, o);
			snprintf (val+len, maxlen-len, ", %u", v_short);
			len += strlen (val+len);
			if (len >= maxlen-1) break;
		}
		break;
	case EXIF_FORMAT_SSHORT:
		v_sshort = exif_get_sshort (e->data, o);
		snprintf (val, maxlen, "%i", v_sshort);
		len = strlen (val);
		for (i = 1; i < e->components; i++) {
			v_sshort = exif_get_short (e->data +
				exif_format_get_size (e->format) *
				i, o);
			snprintf (val+len, maxlen-len, ", %i", v_sshort);
			len += strlen (val+len);
			if (len >= maxlen-1) break;
		}
		break;
	case EXIF_FORMAT_LONG:
		v_long = exif_get_long (e->data, o);
		snprintf (val, maxlen, "%lu", (unsigned long) v_long);
		len = strlen (val);
		for (i = 1; i < e->components; i++) {
			v_long = exif_get_long (e->data +
				exif_format_get_size (e->format) *
				i, o);
			snprintf (val+len, maxlen-len, ", %lu", (unsigned long) v_long);
			len += strlen (val+len);
			if (len >= maxlen-1) break;
		}
		break;
	case EXIF_FORMAT_SLONG:
		v_slong = exif_get_slong (e->data, o);
		snprintf (val, maxlen, "%li", (long) v_slong);
		len = strlen (val);
		for (i = 1; i < e->components; i++) {
			v_slong = exif_get_slong (e->data +
				exif_format_get_size (e->format) * i, o);
			snprintf (val+len, maxlen-len, ", %li", (long) v_slong);
			len += strlen (val+len);
			if (len >= maxlen-1) break;
		}
		break;
	case EXIF_FORMAT_ASCII:
		strncpy (val, (char *) e->data, MIN (maxlen-1, e->size));
		val[MIN (maxlen-1, e->size)] = 0;
		break;
	case EXIF_FORMAT_RATIONAL:
		len = 0;
		for (i = 0; i < e->components; i++) {
			if (i > 0) {
				snprintf (val+len, maxlen-len, ", ");
				len += strlen (val+len);
			}
			v_rat = exif_get_rational (
				e->data + 8 * i, o);
			if (v_rat.denominator) {
				/*
				 * Choose the number of significant digits to
				 * display based on the size of the denominator.
				 * It is scaled so that denominators within the
				 * range 13..120 will show 2 decimal points.
				 */
				int decimals = (int)(log10(v_rat.denominator)-0.08+1.0);
				snprintf (val+len, maxlen-len, "%2.*f",
					  decimals,
					  (double) v_rat.numerator /
					  (double) v_rat.denominator);
			} else
				snprintf (val+len, maxlen-len, "%lu/%lu",
				  (unsigned long) v_rat.numerator,
				  (unsigned long) v_rat.denominator);
			len += strlen (val+len);
			if (len >= maxlen-1) break;
		}
		break;
	case EXIF_FORMAT_SRATIONAL:
		len = 0;
		for (i = 0; i < e->components; i++) {
			if (i > 0) {
				snprintf (val+len, maxlen-len, ", ");
				len += strlen (val+len);
			}
			v_srat = exif_get_srational (
				e->data + 8 * i, o);
			if (v_srat.denominator) {
				int decimals = (int)(log10(abs(v_srat.denominator))-0.08+1.0);
				snprintf (val+len, maxlen-len, "%2.*f",
					  decimals,
					  (double) v_srat.numerator /
					  (double) v_srat.denominator);
			} else
				snprintf (val+len, maxlen-len, "%li/%li",
				  (long) v_srat.numerator,
				  (long) v_srat.denominator);
			len += strlen (val+len);
			if (len >= maxlen-1) break;
		}
		break;
	case EXIF_FORMAT_DOUBLE:
	case EXIF_FORMAT_FLOAT:
	default:
		snprintf (val, maxlen, _("%i bytes unsupported data type"),
			  e->size);
		break;
	}
}


exif_entry_alloc (ExifEntry *e, unsigned int i)
{
	void *d;
	ExifLog *l = NULL;

	if (!e || !e->priv || !i) return NULL;

	d = exif_mem_alloc (e->priv->mem, i);
	if (d) return d;

	if (e->parent && e->parent->parent)
		l = exif_data_get_log (e->parent->parent);
	EXIF_LOG_NO_MEMORY (l, "ExifEntry", i);
	return NULL;
}


static int ch9_postconfig(struct usbtest_dev *dev)
{
	struct usb_interface	*iface = dev->intf;
	struct usb_device	*udev = interface_to_usbdev(iface);
	int			i, alt, retval;

	/* [9.2.3] if there's more than one altsetting, we need to be able to
	 * set and get each one.  mostly trusts the descriptors from usbcore.
	 */
	for (i = 0; i < iface->num_altsetting; i++) {

		/* 9.2.3 constrains the range here */
		alt = iface->altsetting[i].desc.bAlternateSetting;
		if (alt < 0 || alt >= iface->num_altsetting) {
			dev_err(&iface->dev,
					"invalid alt [%d].bAltSetting = %d\n",
					i, alt);
		}

		/* [real world] get/set unimplemented if there's only one */
		if (realworld && iface->num_altsetting == 1)
			continue;

		/* [9.4.10] set_interface */
		retval = set_altsetting(dev, alt);
		if (retval) {
			dev_err(&iface->dev, "can't set_interface = %d, %d\n",
					alt, retval);
			return retval;
		}

		/* [9.4.4] get_interface always works */
		retval = get_altsetting(dev);
		if (retval != alt) {
			dev_err(&iface->dev, "get alt should be %d, was %d\n",
					alt, retval);
			return (retval < 0) ? retval : -EDOM;
		}

	}

	/* [real world] get_config unimplemented if there's only one */
	if (!realworld || udev->descriptor.bNumConfigurations != 1) {
		int	expected = udev->actconfig->desc.bConfigurationValue;

		/* [9.4.2] get_configuration always works
		 * ... although some cheap devices (like one TI Hub I've got)
		 * won't return config descriptors except before set_config.
		 */
		retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
				USB_REQ_GET_CONFIGURATION,
				USB_DIR_IN | USB_RECIP_DEVICE,
				0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
		if (retval != 1 || dev->buf[0] != expected) {
			dev_err(&iface->dev, "get config --> %d %d (1 %d)\n",
				retval, dev->buf[0], expected);
			return (retval < 0) ? retval : -EDOM;
		}
	}

	/* there's always [9.4.3] a device descriptor [9.6.1] */
	retval = usb_get_descriptor(udev, USB_DT_DEVICE, 0,
			dev->buf, sizeof(udev->descriptor));
	if (retval != sizeof(udev->descriptor)) {
		dev_err(&iface->dev, "dev descriptor --> %d\n", retval);
		return (retval < 0) ? retval : -EDOM;
	}

	/*
	 * there's always [9.4.3] a bos device descriptor [9.6.2] in USB
	 * 3.0 spec
	 */
	if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0210) {
		struct usb_bos_descriptor *bos = NULL;
		struct usb_dev_cap_header *header = NULL;
		unsigned total, num, length;
		u8 *buf;

		retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf,
				sizeof(*udev->bos->desc));
		if (retval != sizeof(*udev->bos->desc)) {
			dev_err(&iface->dev, "bos descriptor --> %d\n", retval);
			return (retval < 0) ? retval : -EDOM;
		}

		bos = (struct usb_bos_descriptor *)dev->buf;
		total = le16_to_cpu(bos->wTotalLength);
		num = bos->bNumDeviceCaps;

		if (total > TBUF_SIZE)
			total = TBUF_SIZE;

		/*
		 * get generic device-level capability descriptors [9.6.2]
		 * in USB 3.0 spec
		 */
		retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf,
				total);
		if (retval != total) {
			dev_err(&iface->dev, "bos descriptor set --> %d\n",
					retval);
			return (retval < 0) ? retval : -EDOM;
		}

		length = sizeof(*udev->bos->desc);
		buf = dev->buf;
		for (i = 0; i < num; i++) {
			buf += length;
			if (buf + sizeof(struct usb_dev_cap_header) >
					dev->buf + total)
				break;

			header = (struct usb_dev_cap_header *)buf;
			length = header->bLength;

			if (header->bDescriptorType !=
					USB_DT_DEVICE_CAPABILITY) {
				dev_warn(&udev->dev, "not device capability descriptor, skip\n");
				continue;
			}

			switch (header->bDevCapabilityType) {
			case USB_CAP_TYPE_EXT:
				if (buf + USB_DT_USB_EXT_CAP_SIZE >
						dev->buf + total ||
						!is_good_ext(dev, buf)) {
					dev_err(&iface->dev, "bogus usb 2.0 extension descriptor\n");
					return -EDOM;
				}
				break;
			case USB_SS_CAP_TYPE:
				if (buf + USB_DT_USB_SS_CAP_SIZE >
						dev->buf + total ||
						!is_good_ss_cap(dev, buf)) {
					dev_err(&iface->dev, "bogus superspeed device capability descriptor\n");
					return -EDOM;
				}
				break;
			case CONTAINER_ID_TYPE:
				if (buf + USB_DT_USB_SS_CONTN_ID_SIZE >
						dev->buf + total ||
						!is_good_con_id(dev, buf)) {
					dev_err(&iface->dev, "bogus container id descriptor\n");
					return -EDOM;
				}
				break;
			default:
				break;
			}
		}
	}

	/* there's always [9.4.3] at least one config descriptor [9.6.3] */
	for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
		retval = usb_get_descriptor(udev, USB_DT_CONFIG, i,
				dev->buf, TBUF_SIZE);
		if (!is_good_config(dev, retval)) {
			dev_err(&iface->dev,
					"config [%d] descriptor --> %d\n",
					i, retval);
			return (retval < 0) ? retval : -EDOM;
		}

		/* FIXME cross-checking udev->config[i] to make sure usbcore
		 * parsed it right (etc) would be good testing paranoia
		 */
	}

	/* and sometimes [9.2.6.6] speed dependent descriptors */
	if (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0200) {
		struct usb_qualifier_descriptor *d = NULL;

		/* device qualifier [9.6.2] */
		retval = usb_get_descriptor(udev,
				USB_DT_DEVICE_QUALIFIER, 0, dev->buf,
				sizeof(struct usb_qualifier_descriptor));
		if (retval == -EPIPE) {
			if (udev->speed == USB_SPEED_HIGH) {
				dev_err(&iface->dev,
						"hs dev qualifier --> %d\n",
						retval);
				return retval;
			}
			/* usb2.0 but not high-speed capable; fine */
		} else if (retval != sizeof(struct usb_qualifier_descriptor)) {
			dev_err(&iface->dev, "dev qualifier --> %d\n", retval);
			return (retval < 0) ? retval : -EDOM;
		} else
			d = (struct usb_qualifier_descriptor *) dev->buf;

		/* might not have [9.6.2] any other-speed configs [9.6.4] */
		if (d) {
			unsigned max = d->bNumConfigurations;
			for (i = 0; i < max; i++) {
				retval = usb_get_descriptor(udev,
					USB_DT_OTHER_SPEED_CONFIG, i,
					dev->buf, TBUF_SIZE);
				if (!is_good_config(dev, retval)) {
					dev_err(&iface->dev,
						"other speed config --> %d\n",
						retval);
					return (retval < 0) ? retval : -EDOM;
				}
			}
		}
	}
	/* FIXME fetch strings from at least the device descriptor */

	/* [9.4.5] get_status always works */
	retval = usb_get_std_status(udev, USB_RECIP_DEVICE, 0, dev->buf);
	if (retval) {
		dev_err(&iface->dev, "get dev status --> %d\n", retval);
		return retval;
	}

	/* FIXME configuration.bmAttributes says if we could try to set/clear
	 * the device's remote wakeup feature ... if we can, test that here
	 */

	retval = usb_get_std_status(udev, USB_RECIP_INTERFACE,
			iface->altsetting[0].desc.bInterfaceNumber, dev->buf);
	if (retval) {
		dev_err(&iface->dev, "get interface status --> %d\n", retval);
		return retval;
	}
	/* FIXME get status for each endpoint in the interface */

	return 0;
}


static struct urb *iso_alloc_urb(
	struct usb_device	*udev,
	int			pipe,
	struct usb_endpoint_descriptor	*desc,
	long			bytes,
	unsigned offset
)
{
	struct urb		*urb;
	unsigned		i, maxp, packets;

	if (bytes < 0 || !desc)
		return NULL;

	maxp = usb_endpoint_maxp(desc);
	if (udev->speed >= USB_SPEED_SUPER)
		maxp *= ss_isoc_get_packet_num(udev, pipe);
	else
		maxp *= usb_endpoint_maxp_mult(desc);

	packets = DIV_ROUND_UP(bytes, maxp);

	urb = usb_alloc_urb(packets, GFP_KERNEL);
	if (!urb)
		return urb;
	urb->dev = udev;
	urb->pipe = pipe;

	urb->number_of_packets = packets;
	urb->transfer_buffer_length = bytes;
	urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset,
							GFP_KERNEL,
							&urb->transfer_dma);
	if (!urb->transfer_buffer) {
		usb_free_urb(urb);
		return NULL;
	}
	if (offset) {
		memset(urb->transfer_buffer, GUARD_BYTE, offset);
		urb->transfer_buffer += offset;
		urb->transfer_dma += offset;
	}
	/* For inbound transfers use guard byte so that test fails if
		data not correctly copied */
	memset(urb->transfer_buffer,
			usb_pipein(urb->pipe) ? GUARD_BYTE : 0,
			bytes);

	for (i = 0; i < packets; i++) {
		/* here, only the last packet will be short */
		urb->iso_frame_desc[i].length = min((unsigned) bytes, maxp);
		bytes -= urb->iso_frame_desc[i].length;

		urb->iso_frame_desc[i].offset = maxp * i;
	}

	urb->complete = complicated_callback;
	/* urb->context = SET BY CALLER */
	urb->interval = 1 << (desc->bInterval - 1);
	urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
	return urb;
}


static int register_update_efi_random_seed(void)
{
	if (efi.rng_seed == EFI_INVALID_TABLE_ADDR)
		return 0;
	return register_reboot_notifier(&efi_random_seed_nb);
}


static int generic_ops_register(void)
{
	generic_ops.get_variable = efi.get_variable;
	generic_ops.set_variable = efi.set_variable;
	generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
	generic_ops.get_next_variable = efi.get_next_variable;
	generic_ops.query_variable_store = efi_query_variable_store;

	return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
}


static void __exit acpi_configfs_exit(void)
{
	configfs_unregister_default_group(acpi_table_group);
	configfs_unregister_subsystem(&acpi_configfs);
}


static int __init acpi_configfs_init(void)
{
	int ret;
	struct config_group *root = &acpi_configfs.su_group;

	config_group_init(root);

	ret = configfs_register_subsystem(&acpi_configfs);
	if (ret)
		return ret;

	acpi_table_group = configfs_register_default_group(root, "table",
							   &acpi_tables_type);
	return PTR_ERR_OR_ZERO(acpi_table_group);
}


int LibRaw::thumbOK(INT64 maxsz)
{
  if (!ID.input)
    return 0;
  if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 &&
                       load_raw == &LibRaw::broadcom_load_raw) // RPi
  )
    return 0;
  INT64 fsize = ID.input->size();
  if (fsize > 0x7fffffffU)
    return 0; // No thumb for raw > 2Gb
  int tsize = 0;
  int tcol = (T.tcolors > 0 && T.tcolors < 4) ? T.tcolors : 3;
  if (write_thumb == &LibRaw::jpeg_thumb)
    tsize = T.tlength;
  else if (write_thumb == &LibRaw::ppm_thumb)
    tsize = tcol * T.twidth * T.theight;
  else if (write_thumb == &LibRaw::ppm16_thumb)
    tsize = tcol * T.twidth * T.theight *
            ((imgdata.params.raw_processing_options &
              LIBRAW_PROCESSING_USE_PPM16_THUMBS)
                 ? 2
                 : 1);
#ifdef USE_X3FTOOLS
  else if (write_thumb == &LibRaw::x3f_thumb_loader)
  {
    tsize = x3f_thumb_size();
  }
#endif
  else // Kodak => no check
    tsize = 1;
  if (tsize < 0)
    return 0;
  if (maxsz > 0 && tsize > maxsz)
    return 0;
  return (tsize + ID.toffset <= fsize) ? 1 : 0;
}


static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode,
						   struct buffer_head *bh)
{
	struct ext4_dir_entry_tail *t;

#ifdef PARANOID
	struct ext4_dir_entry *d, *top;

	d = (struct ext4_dir_entry *)bh->b_data;
	top = (struct ext4_dir_entry *)(bh->b_data +
		(EXT4_BLOCK_SIZE(inode->i_sb) -
		 sizeof(struct ext4_dir_entry_tail)));
	while (d < top && d->rec_len)
		d = (struct ext4_dir_entry *)(((void *)d) +
		    le16_to_cpu(d->rec_len));

	if (d != top)
		return NULL;

	t = (struct ext4_dir_entry_tail *)d;
#else
	t = EXT4_DIRENT_TAIL(bh->b_data, EXT4_BLOCK_SIZE(inode->i_sb));
#endif

	if (t->det_reserved_zero1 ||
	    le16_to_cpu(t->det_rec_len) != sizeof(struct ext4_dir_entry_tail) ||
	    t->det_reserved_zero2 ||
	    t->det_reserved_ft != EXT4_FT_DIR_CSUM)
		return NULL;

	return t;
}


static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
		       struct inode *new_dir, struct dentry *new_dentry,
		       unsigned int flags)
{
	handle_t *handle = NULL;
	struct ext4_renament old = {
		.dir = old_dir,
		.dentry = old_dentry,
		.inode = d_inode(old_dentry),
	};
	struct ext4_renament new = {
		.dir = new_dir,
		.dentry = new_dentry,
		.inode = d_inode(new_dentry),
	};
	int force_reread;
	int retval;
	struct inode *whiteout = NULL;
	int credits;
	u8 old_file_type;

	if (new.inode && new.inode->i_nlink == 0) {
		EXT4_ERROR_INODE(new.inode,
				 "target of rename is already freed");
		return -EFSCORRUPTED;
	}

	if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) &&
	    (!projid_eq(EXT4_I(new_dir)->i_projid,
			EXT4_I(old_dentry->d_inode)->i_projid)))
		return -EXDEV;

	retval = dquot_initialize(old.dir);
	if (retval)
		return retval;
	retval = dquot_initialize(new.dir);
	if (retval)
		return retval;

	/* Initialize quotas before so that eventual writes go
	 * in separate transaction */
	if (new.inode) {
		retval = dquot_initialize(new.inode);
		if (retval)
			return retval;
	}

	old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
	if (IS_ERR(old.bh))
		return PTR_ERR(old.bh);
	/*
	 *  Check for inode number is _not_ due to possible IO errors.
	 *  We might rmdir the source, keep it as pwd of some process
	 *  and merrily kill the link to whatever was created under the
	 *  same name. Goodbye sticky bit ;-<
	 */
	retval = -ENOENT;
	if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino)
		goto end_rename;

	new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
				 &new.de, &new.inlined);
	if (IS_ERR(new.bh)) {
		retval = PTR_ERR(new.bh);
		new.bh = NULL;
		goto end_rename;
	}
	if (new.bh) {
		if (!new.inode) {
			brelse(new.bh);
			new.bh = NULL;
		}
	}
	if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC))
		ext4_alloc_da_blocks(old.inode);

	credits = (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) +
		   EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2);
	if (!(flags & RENAME_WHITEOUT)) {
		handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits);
		if (IS_ERR(handle)) {
			retval = PTR_ERR(handle);
			handle = NULL;
			goto end_rename;
		}
	} else {
		whiteout = ext4_whiteout_for_rename(&old, credits, &handle);
		if (IS_ERR(whiteout)) {
			retval = PTR_ERR(whiteout);
			whiteout = NULL;
			goto end_rename;
		}
	}

	if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir))
		ext4_handle_sync(handle);

	if (S_ISDIR(old.inode->i_mode)) {
		if (new.inode) {
			retval = -ENOTEMPTY;
			if (!ext4_empty_dir(new.inode))
				goto end_rename;
		} else {
			retval = -EMLINK;
			if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir))
				goto end_rename;
		}
		retval = ext4_rename_dir_prepare(handle, &old);
		if (retval)
			goto end_rename;
	}
	/*
	 * If we're renaming a file within an inline_data dir and adding or
	 * setting the new dirent causes a conversion from inline_data to
	 * extents/blockmap, we need to force the dirent delete code to
	 * re-read the directory, or else we end up trying to delete a dirent
	 * from what is now the extent tree root (or a block map).
	 */
	force_reread = (new.dir->i_ino == old.dir->i_ino &&
			ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));

	old_file_type = old.de->file_type;
	if (whiteout) {
		/*
		 * Do this before adding a new entry, so the old entry is sure
		 * to be still pointing to the valid old entry.
		 */
		retval = ext4_setent(handle, &old, whiteout->i_ino,
				     EXT4_FT_CHRDEV);
		if (retval)
			goto end_rename;
		retval = ext4_mark_inode_dirty(handle, whiteout);
		if (unlikely(retval))
			goto end_rename;
	}
	if (!new.bh) {
		retval = ext4_add_entry(handle, new.dentry, old.inode);
		if (retval)
			goto end_rename;
	} else {
		retval = ext4_setent(handle, &new,
				     old.inode->i_ino, old_file_type);
		if (retval)
			goto end_rename;
	}
	if (force_reread)
		force_reread = !ext4_test_inode_flag(new.dir,
						     EXT4_INODE_INLINE_DATA);

	/*
	 * Like most other Unix systems, set the ctime for inodes on a
	 * rename.
	 */
	old.inode->i_ctime = current_time(old.inode);
	retval = ext4_mark_inode_dirty(handle, old.inode);
	if (unlikely(retval))
		goto end_rename;

	if (!whiteout) {
		/*
		 * ok, that's it
		 */
		ext4_rename_delete(handle, &old, force_reread);
	}

	if (new.inode) {
		ext4_dec_count(handle, new.inode);
		new.inode->i_ctime = current_time(new.inode);
	}
	old.dir->i_ctime = old.dir->i_mtime = current_time(old.dir);
	ext4_update_dx_flag(old.dir);
	if (old.dir_bh) {
		retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
		if (retval)
			goto end_rename;

		ext4_dec_count(handle, old.dir);
		if (new.inode) {
			/* checked ext4_empty_dir above, can't have another
			 * parent, ext4_dec_count() won't work for many-linked
			 * dirs */
			clear_nlink(new.inode);
		} else {
			ext4_inc_count(handle, new.dir);
			ext4_update_dx_flag(new.dir);
			retval = ext4_mark_inode_dirty(handle, new.dir);
			if (unlikely(retval))
				goto end_rename;
		}
	}
	retval = ext4_mark_inode_dirty(handle, old.dir);
	if (unlikely(retval))
		goto end_rename;
	if (new.inode) {
		retval = ext4_mark_inode_dirty(handle, new.inode);
		if (unlikely(retval))
			goto end_rename;
		if (!new.inode->i_nlink)
			ext4_orphan_add(handle, new.inode);
	}
	retval = 0;

end_rename:
	brelse(old.dir_bh);
	brelse(old.bh);
	brelse(new.bh);
	if (whiteout) {
		if (retval)
			drop_nlink(whiteout);
		unlock_new_inode(whiteout);
		iput(whiteout);
	}
	if (handle)
		ext4_journal_stop(handle);
	return retval;
}


struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
			     struct dx_entry *entries, int levels)
{
	unsigned blocksize = dir->i_sb->s_blocksize;
	unsigned count = dx_get_count(entries), names = 0, space = 0, i;
	unsigned bcount = 0;
	struct buffer_head *bh;
	printk("%i indexed blocks...\n", count);
	for (i = 0; i < count; i++, entries++)
	{
		ext4_lblk_t block = dx_get_block(entries);
		ext4_lblk_t hash  = i ? dx_get_hash(entries): 0;
		u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash;
		struct stats stats;
		printk("%s%3u:%03u hash %8x/%8x ",levels?"":"   ", i, block, hash, range);
		bh = ext4_bread(NULL,dir, block, 0);
		if (!bh || IS_ERR(bh))
			continue;
		stats = levels?
		   dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1):
		   dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *)
			bh->b_data, blocksize, 0);
		names += stats.names;
		space += stats.space;
		bcount += stats.bcount;
		brelse(bh);
	}
	if (bcount)
		printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n",
		       levels ? "" : "   ", names, space/bcount,
		       (space/bcount)*100/blocksize);
	return (struct stats) { names, space, bcount};
}


static int ext4_symlink(struct inode *dir,
			struct dentry *dentry, const char *symname)
{
	handle_t *handle;
	struct inode *inode;
	int err, len = strlen(symname);
	int credits;
	struct fscrypt_str disk_link;

	if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
		return -EIO;

	err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
				      &disk_link);
	if (err)
		return err;

	err = dquot_initialize(dir);
	if (err)
		return err;

	if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
		/*
		 * For non-fast symlinks, we just allocate inode and put it on
		 * orphan list in the first transaction => we need bitmap,
		 * group descriptor, sb, inode block, quota blocks, and
		 * possibly selinux xattr blocks.
		 */
		credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
			  EXT4_XATTR_TRANS_BLOCKS;
	} else {
		/*
		 * Fast symlink. We have to add entry to directory
		 * (EXT4_DATA_TRANS_BLOCKS + EXT4_INDEX_EXTRA_TRANS_BLOCKS),
		 * allocate new inode (bitmap, group descriptor, inode block,
		 * quota blocks, sb is already counted in previous macros).
		 */
		credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
			  EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3;
	}

	inode = ext4_new_inode_start_handle(dir, S_IFLNK|S_IRWXUGO,
					    &dentry->d_name, 0, NULL,
					    EXT4_HT_DIR, credits);
	handle = ext4_journal_current_handle();
	if (IS_ERR(inode)) {
		if (handle)
			ext4_journal_stop(handle);
		return PTR_ERR(inode);
	}

	if (IS_ENCRYPTED(inode)) {
		err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
		if (err)
			goto err_drop_inode;
		inode->i_op = &ext4_encrypted_symlink_inode_operations;
	}

	if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
		if (!IS_ENCRYPTED(inode))
			inode->i_op = &ext4_symlink_inode_operations;
		inode_nohighmem(inode);
		ext4_set_aops(inode);
		/*
		 * We cannot call page_symlink() with transaction started
		 * because it calls into ext4_write_begin() which can wait
		 * for transaction commit if we are running out of space
		 * and thus we deadlock. So we have to stop transaction now
		 * and restart it when symlink contents is written.
		 *
		 * To keep fs consistent in case of crash, we have to put inode
		 * to orphan list in the mean time.
		 */
		drop_nlink(inode);
		err = ext4_orphan_add(handle, inode);
		ext4_journal_stop(handle);
		handle = NULL;
		if (err)
			goto err_drop_inode;
		err = __page_symlink(inode, disk_link.name, disk_link.len, 1);
		if (err)
			goto err_drop_inode;
		/*
		 * Now inode is being linked into dir (EXT4_DATA_TRANS_BLOCKS
		 * + EXT4_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
		 */
		handle = ext4_journal_start(dir, EXT4_HT_DIR,
				EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
				EXT4_INDEX_EXTRA_TRANS_BLOCKS + 1);
		if (IS_ERR(handle)) {
			err = PTR_ERR(handle);
			handle = NULL;
			goto err_drop_inode;
		}
		set_nlink(inode, 1);
		err = ext4_orphan_del(handle, inode);
		if (err)
			goto err_drop_inode;
	} else {
		/* clear the extent format for fast symlink */
		ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
		if (!IS_ENCRYPTED(inode)) {
			inode->i_op = &ext4_fast_symlink_inode_operations;
			inode->i_link = (char *)&EXT4_I(inode)->i_data;
		}
		memcpy((char *)&EXT4_I(inode)->i_data, disk_link.name,
		       disk_link.len);
		inode->i_size = disk_link.len - 1;
	}
	EXT4_I(inode)->i_disksize = inode->i_size;
	err = ext4_add_nondir(handle, dentry, &inode);
	if (handle)
		ext4_journal_stop(handle);
	if (inode)
		iput(inode);
	goto out_free_encrypted_link;

err_drop_inode:
	if (handle)
		ext4_journal_stop(handle);
	clear_nlink(inode);
	unlock_new_inode(inode);
	iput(inode);
out_free_encrypted_link:
	if (disk_link.name != (unsigned char *)symname)
		kfree(disk_link.name);
	return err;
}


static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
						ext4_lblk_t block,
						dirblock_type_t type,
						const char *func,
						unsigned int line)
{
	struct buffer_head *bh;
	struct ext4_dir_entry *dirent;
	int is_dx_block = 0;

	if (ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_EIO))
		bh = ERR_PTR(-EIO);
	else
		bh = ext4_bread(NULL, inode, block, 0);
	if (IS_ERR(bh)) {
		__ext4_warning(inode->i_sb, func, line,
			       "inode #%lu: lblock %lu: comm %s: "
			       "error %ld reading directory block",
			       inode->i_ino, (unsigned long)block,
			       current->comm, PTR_ERR(bh));

		return bh;
	}
	if (!bh && (type == INDEX || type == DIRENT_HTREE)) {
		ext4_error_inode(inode, func, line, block,
				 "Directory hole found for htree %s block",
				 (type == INDEX) ? "index" : "leaf");
		return ERR_PTR(-EFSCORRUPTED);
	}
	if (!bh)
		return NULL;
	dirent = (struct ext4_dir_entry *) bh->b_data;
	/* Determine whether or not we have an index block */
	if (is_dx(inode)) {
		if (block == 0)
			is_dx_block = 1;
		else if (ext4_rec_len_from_disk(dirent->rec_len,
						inode->i_sb->s_blocksize) ==
			 inode->i_sb->s_blocksize)
			is_dx_block = 1;
	}
	if (!is_dx_block && type == INDEX) {
		ext4_error_inode(inode, func, line, block,
		       "directory leaf block found instead of index block");
		brelse(bh);
		return ERR_PTR(-EFSCORRUPTED);
	}
	if (!ext4_has_metadata_csum(inode->i_sb) ||
	    buffer_verified(bh))
		return bh;

	/*
	 * An empty leaf block can get mistaken for a index block; for
	 * this reason, we can only check the index checksum when the
	 * caller is sure it should be an index block.
	 */
	if (is_dx_block && type == INDEX) {
		if (ext4_dx_csum_verify(inode, dirent) &&
		    !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC))
			set_buffer_verified(bh);
		else {
			ext4_error_inode_err(inode, func, line, block,
					     EFSBADCRC,
					     "Directory index failed checksum");
			brelse(bh);
			return ERR_PTR(-EFSBADCRC);
		}
	}
	if (!is_dx_block) {
		if (ext4_dirblock_csum_verify(inode, bh) &&
		    !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC))
			set_buffer_verified(bh);
		else {
			ext4_error_inode_err(inode, func, line, block,
					     EFSBADCRC,
					     "Directory block failed checksum");
			brelse(bh);
			return ERR_PTR(-EFSBADCRC);
		}
	}
	return bh;
}


static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
			    struct inode *dir,
			    struct inode *inode, struct buffer_head *bh)
{
	struct buffer_head *bh2;
	struct dx_root	*root;
	struct dx_frame	frames[EXT4_HTREE_LEVEL], *frame;
	struct dx_entry *entries;
	struct ext4_dir_entry_2	*de, *de2;
	char		*data2, *top;
	unsigned	len;
	int		retval;
	unsigned	blocksize;
	ext4_lblk_t  block;
	struct fake_dirent *fde;
	int csum_size = 0;

	if (ext4_has_metadata_csum(inode->i_sb))
		csum_size = sizeof(struct ext4_dir_entry_tail);

	blocksize =  dir->i_sb->s_blocksize;
	dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino));
	BUFFER_TRACE(bh, "get_write_access");
	retval = ext4_journal_get_write_access(handle, bh);
	if (retval) {
		ext4_std_error(dir->i_sb, retval);
		brelse(bh);
		return retval;
	}
	root = (struct dx_root *) bh->b_data;

	/* The 0th block becomes the root, move the dirents out */
	fde = &root->dotdot;
	de = (struct ext4_dir_entry_2 *)((char *)fde +
		ext4_rec_len_from_disk(fde->rec_len, blocksize));
	if ((char *) de >= (((char *) root) + blocksize)) {
		EXT4_ERROR_INODE(dir, "invalid rec_len for '..'");
		brelse(bh);
		return -EFSCORRUPTED;
	}
	len = ((char *) root) + (blocksize - csum_size) - (char *) de;

	/* Allocate new block for the 0th block's dirents */
	bh2 = ext4_append(handle, dir, &block);
	if (IS_ERR(bh2)) {
		brelse(bh);
		return PTR_ERR(bh2);
	}
	ext4_set_inode_flag(dir, EXT4_INODE_INDEX);
	data2 = bh2->b_data;

	memcpy(data2, de, len);
	de = (struct ext4_dir_entry_2 *) data2;
	top = data2 + len;
	while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top)
		de = de2;
	de->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) -
					   (char *) de, blocksize);

	if (csum_size)
		ext4_initialize_dirent_tail(bh2, blocksize);

	/* Initialize the root; the dot dirents already exist */
	de = (struct ext4_dir_entry_2 *) (&root->dotdot);
	de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2),
					   blocksize);
	memset (&root->info, 0, sizeof(root->info));
	root->info.info_length = sizeof(root->info);
	root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
	entries = root->entries;
	dx_set_block(entries, 1);
	dx_set_count(entries, 1);
	dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info)));

	/* Initialize as for dx_probe */
	fname->hinfo.hash_version = root->info.hash_version;
	if (fname->hinfo.hash_version <= DX_HASH_TEA)
		fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
	fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
	ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), &fname->hinfo);

	memset(frames, 0, sizeof(frames));
	frame = frames;
	frame->entries = entries;
	frame->at = entries;
	frame->bh = bh;

	retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
	if (retval)
		goto out_frames;
	retval = ext4_handle_dirty_dirblock(handle, dir, bh2);
	if (retval)
		goto out_frames;

	de = do_split(handle,dir, &bh2, frame, &fname->hinfo);
	if (IS_ERR(de)) {
		retval = PTR_ERR(de);
		goto out_frames;
	}

	retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2);
out_frames:
	/*
	 * Even if the block split failed, we have to properly write
	 * out all the changes we did so far. Otherwise we can end up
	 * with corrupted filesystem.
	 */
	if (retval)
		ext4_mark_inode_dirty(handle, dir);
	dx_release(frames);
	brelse(bh2);
	return retval;
}


static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent)
{
	int retval;

	ent->dir_bh = ext4_get_first_dir_block(handle, ent->inode,
					      &retval, &ent->parent_de,
					      &ent->dir_inlined);
	if (!ent->dir_bh)
		return retval;
	if (le32_to_cpu(ent->parent_de->inode) != ent->dir->i_ino)
		return -EFSCORRUPTED;
	BUFFER_TRACE(ent->dir_bh, "get_write_access");
	return ext4_journal_get_write_access(handle, ent->dir_bh);
}


static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent,
				  unsigned dir_ino)
{
	int retval;

	ent->parent_de->inode = cpu_to_le32(dir_ino);
	BUFFER_TRACE(ent->dir_bh, "call ext4_handle_dirty_metadata");
	if (!ent->dir_inlined) {
		if (is_dx(ent->inode)) {
			retval = ext4_handle_dirty_dx_node(handle,
							   ent->inode,
							   ent->dir_bh);
		} else {
			retval = ext4_handle_dirty_dirblock(handle, ent->inode,
							    ent->dir_bh);
		}
	} else {
		retval = ext4_mark_inode_dirty(handle, ent->inode);
	}
	if (retval) {
		ext4_std_error(ent->dir->i_sb, retval);
		return retval;
	}
	return 0;
}


static void dx_release(struct dx_frame *frames)
{
	struct dx_root_info *info;
	int i;
	unsigned int indirect_levels;

	if (frames[0].bh == NULL)
		return;

	info = &((struct dx_root *)frames[0].bh->b_data)->info;
	/* save local copy, "info" may be freed after brelse() */
	indirect_levels = info->indirect_levels;
	for (i = 0; i <= indirect_levels; i++) {
		if (frames[i].bh == NULL)
			break;
		brelse(frames[i].bh);
		frames[i].bh = NULL;
	}
}


static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
	handle_t *handle;
	struct inode *inode;
	int err, retries = 0;

	err = dquot_initialize(dir);
	if (err)
		return err;

retry:
	inode = ext4_new_inode_start_handle(dir, mode,
					    NULL, 0, NULL,
					    EXT4_HT_DIR,
			EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
			  4 + EXT4_XATTR_TRANS_BLOCKS);
	handle = ext4_journal_current_handle();
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		inode->i_op = &ext4_file_inode_operations;
		inode->i_fop = &ext4_file_operations;
		ext4_set_aops(inode);
		d_tmpfile(dentry, inode);
		err = ext4_orphan_add(handle, inode);
		if (err)
			goto err_unlock_inode;
		mark_inode_dirty(inode);
		unlock_new_inode(inode);
	}
	if (handle)
		ext4_journal_stop(handle);
	if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
		goto retry;
	return err;
err_unlock_inode:
	ext4_journal_stop(handle);
	unlock_new_inode(inode);
	return err;
}


CACHE_GLYPH_ORDER* copy_cache_glyph_order(rdpContext* context, const CACHE_GLYPH_ORDER* glyph)
{
	size_t x;
	CACHE_GLYPH_ORDER* dst = calloc(1, sizeof(CACHE_GLYPH_ORDER));

	if (!dst || !glyph)
		goto fail;

	*dst = *glyph;

	for (x = 0; x < glyph->cGlyphs; x++)
	{
		const GLYPH_DATA* src = &glyph->glyphData[x];
		GLYPH_DATA* data = &dst->glyphData[x];

		if (src->aj)
		{
			const size_t size = src->cb;
			data->aj = malloc(size);

			if (!data->aj)
				goto fail;

			memcpy(data->aj, src->aj, size);
		}
	}

	if (glyph->unicodeCharacters)
	{
		if (glyph->cGlyphs == 0)
			goto fail;

		dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));

		if (!dst->unicodeCharacters)
			goto fail;

		memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
	}

	return dst;
fail:
	free_cache_glyph_order(context, dst);
	return NULL;
}


void glyph_cache_free(rdpGlyphCache* glyphCache)
{
	if (glyphCache)
	{
		int i;
		GLYPH_CACHE* cache = glyphCache->glyphCache;

		for (i = 0; i < 10; i++)
		{
			UINT32 j;
			rdpGlyph** entries = cache[i].entries;

			if (!entries)
				continue;

			for (j = 0; j < cache[i].number; j++)
			{
				rdpGlyph* glyph = entries[j];

				if (glyph)
				{
					glyph->Free(glyphCache->context, glyph);
					entries[j] = NULL;
				}
			}

			free(entries);
			cache[i].entries = NULL;
		}

		if (glyphCache->fragCache.entries)
		{
			for (i = 0; i < 256; i++)
			{
				free(glyphCache->fragCache.entries[i].fragment);
				glyphCache->fragCache.entries[i].fragment = NULL;
			}
		}

		free(glyphCache->fragCache.entries);
		free(glyphCache);
	}
}


BOOL update_write_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3,
                                        UINT16* flags)
{
	BOOL rc;
	BYTE bitsPerPixelId;
	BITMAP_DATA_EX* bitmapData;

	if (!Stream_EnsureRemainingCapacity(
	        s, update_approximate_cache_bitmap_v3_order(cache_bitmap_v3, flags)))
		return FALSE;

	bitmapData = &cache_bitmap_v3->bitmapData;
	bitsPerPixelId = get_bpp_bmf(cache_bitmap_v3->bpp, &rc);
	if (!rc)
		return FALSE;
	*flags = (cache_bitmap_v3->cacheId & 0x00000003) |
	         ((cache_bitmap_v3->flags << 7) & 0x0000FF80) | ((bitsPerPixelId << 3) & 0x00000078);
	Stream_Write_UINT16(s, cache_bitmap_v3->cacheIndex); /* cacheIndex (2 bytes) */
	Stream_Write_UINT32(s, cache_bitmap_v3->key1);       /* key1 (4 bytes) */
	Stream_Write_UINT32(s, cache_bitmap_v3->key2);       /* key2 (4 bytes) */
	Stream_Write_UINT8(s, bitmapData->bpp);
	Stream_Write_UINT8(s, 0);                   /* reserved1 (1 byte) */
	Stream_Write_UINT8(s, 0);                   /* reserved2 (1 byte) */
	Stream_Write_UINT8(s, bitmapData->codecID); /* codecID (1 byte) */
	Stream_Write_UINT16(s, bitmapData->width);  /* width (2 bytes) */
	Stream_Write_UINT16(s, bitmapData->height); /* height (2 bytes) */
	Stream_Write_UINT32(s, bitmapData->length); /* length (4 bytes) */
	Stream_Write(s, bitmapData->data, bitmapData->length);
	return TRUE;
}


static BOOL update_read_polyline_order(wStream* s, const ORDER_INFO* orderInfo,
                                       POLYLINE_ORDER* polyline)
{
	UINT16 word;
	UINT32 new_num = polyline->numDeltaEntries;
	ORDER_FIELD_COORD(1, polyline->xStart);
	ORDER_FIELD_COORD(2, polyline->yStart);
	ORDER_FIELD_BYTE(3, polyline->bRop2);
	ORDER_FIELD_UINT16(4, word);
	ORDER_FIELD_COLOR(orderInfo, s, 5, &polyline->penColor);
	ORDER_FIELD_BYTE(6, new_num);

	if (orderInfo->fieldFlags & ORDER_FIELD_07)
	{
		DELTA_POINT* new_points;

		if (new_num == 0)
			return FALSE;

		if (Stream_GetRemainingLength(s) < 1)
		{
			WLog_ERR(TAG, "Stream_GetRemainingLength(s) < 1");
			return FALSE;
		}

		Stream_Read_UINT8(s, polyline->cbData);
		new_points = (DELTA_POINT*)realloc(polyline->points, sizeof(DELTA_POINT) * new_num);

		if (!new_points)
		{
			WLog_ERR(TAG, "realloc(%" PRIu32 ") failed", new_num);
			return FALSE;
		}

		polyline->points = new_points;
		polyline->numDeltaEntries = new_num;
		return update_read_delta_points(s, polyline->points, polyline->numDeltaEntries,
		                                polyline->xStart, polyline->yStart);
	}

	return TRUE;
}


static BOOL update_read_fast_glyph_order(wStream* s, const ORDER_INFO* orderInfo,
                                         FAST_GLYPH_ORDER* fastGlyph)
{
	GLYPH_DATA_V2* glyph = &fastGlyph->glyphData;
	ORDER_FIELD_BYTE(1, fastGlyph->cacheId);
	ORDER_FIELD_2BYTE(2, fastGlyph->ulCharInc, fastGlyph->flAccel);
	ORDER_FIELD_COLOR(orderInfo, s, 3, &fastGlyph->backColor);
	ORDER_FIELD_COLOR(orderInfo, s, 4, &fastGlyph->foreColor);
	ORDER_FIELD_COORD(5, fastGlyph->bkLeft);
	ORDER_FIELD_COORD(6, fastGlyph->bkTop);
	ORDER_FIELD_COORD(7, fastGlyph->bkRight);
	ORDER_FIELD_COORD(8, fastGlyph->bkBottom);
	ORDER_FIELD_COORD(9, fastGlyph->opLeft);
	ORDER_FIELD_COORD(10, fastGlyph->opTop);
	ORDER_FIELD_COORD(11, fastGlyph->opRight);
	ORDER_FIELD_COORD(12, fastGlyph->opBottom);
	ORDER_FIELD_COORD(13, fastGlyph->x);
	ORDER_FIELD_COORD(14, fastGlyph->y);

	if (orderInfo->fieldFlags & ORDER_FIELD_15)
	{
		if (Stream_GetRemainingLength(s) < 1)
			return FALSE;

		Stream_Read_UINT8(s, fastGlyph->cbData);

		if (Stream_GetRemainingLength(s) < fastGlyph->cbData)
			return FALSE;

		CopyMemory(fastGlyph->data, Stream_Pointer(s), fastGlyph->cbData);
		if (Stream_GetRemainingLength(s) < fastGlyph->cbData)
			return FALSE;

		if (!Stream_SafeSeek(s, 1))
			return FALSE;

		if (fastGlyph->cbData > 1)
		{
			UINT32 new_cb;
			/* parse optional glyph data */
			glyph->cacheIndex = fastGlyph->data[0];

			if (!update_read_2byte_signed(s, &glyph->x) ||
			    !update_read_2byte_signed(s, &glyph->y) ||
			    !update_read_2byte_unsigned(s, &glyph->cx) ||
			    !update_read_2byte_unsigned(s, &glyph->cy))
				return FALSE;

			glyph->cb = ((glyph->cx + 7) / 8) * glyph->cy;
			glyph->cb += ((glyph->cb % 4) > 0) ? 4 - (glyph->cb % 4) : 0;
			new_cb = ((glyph->cx + 7) / 8) * glyph->cy;
			new_cb += ((new_cb % 4) > 0) ? 4 - (new_cb % 4) : 0;

			if (fastGlyph->cbData < new_cb)
				return FALSE;

			if (new_cb > 0)
			{
				BYTE* new_aj;
				new_aj = (BYTE*)realloc(glyph->aj, new_cb);

				if (!new_aj)
					return FALSE;

				glyph->aj = new_aj;
				glyph->cb = new_cb;
				Stream_Read(s, glyph->aj, glyph->cb);
			}
			Stream_Seek(s, fastGlyph->cbData - new_cb);
		}
	}

	return TRUE;
}


int shadow_server_stop(rdpShadowServer* server)
{
	if (!server)
		return -1;

	if (server->thread)
	{
		SetEvent(server->StopEvent);
		WaitForSingleObject(server->thread, INFINITE);
		CloseHandle(server->thread);
		server->thread = NULL;
		server->listener->Close(server->listener);
	}

	if (server->screen)
	{
		shadow_screen_free(server->screen);
		server->screen = NULL;
	}

	if (server->capture)
	{
		shadow_capture_free(server->capture);
		server->capture = NULL;
	}

	return 0;
}


static DWORD WINAPI shadow_server_thread(LPVOID arg)
{
	rdpShadowServer* server = (rdpShadowServer*)arg;
	BOOL running = TRUE;
	DWORD status;
	freerdp_listener* listener = server->listener;
	shadow_subsystem_start(server->subsystem);

	while (running)
	{
		HANDLE events[32];
		DWORD nCount = 0;
		events[nCount++] = server->StopEvent;
		nCount += listener->GetEventHandles(listener, &events[nCount], 32 - nCount);

		if (nCount <= 1)
		{
			WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
			break;
		}

		status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);

		switch (status)
		{
			case WAIT_FAILED:
			case WAIT_OBJECT_0:
				running = FALSE;
				break;

			default:
			{
				if (!listener->CheckFileDescriptor(listener))
				{
					WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
					running = FALSE;
				}
				else
				{
#ifdef _WIN32
					Sleep(100); /* FIXME: listener event handles */
#endif
				}
			}
			break;
		}
	}

	listener->Close(listener);
	shadow_subsystem_stop(server->subsystem);

	/* Signal to the clients that server is being stopped and wait for them
	 * to disconnect. */
	if (shadow_client_boardcast_quit(server, 0))
	{
		while (ArrayList_Count(server->clients) > 0)
		{
			Sleep(100);
		}
	}

	ExitThread(0);
	return 0;
}


TRIO_PUBLIC_STRING int trio_copy TRIO_ARGS2((target, source), char* target, TRIO_CONST char* source)
{
	assert(target);
	assert(source);

	(void)strcpy(target, source);
	return TRUE;
}


TRIO_PRIVATE void TrioOutStreamStringDynamic TRIO_ARGS2((self, output), trio_class_t* self,
                                                        int output)
{
	assert(VALID(self));
	assert(VALID(self->location));

	if (self->error == 0)
	{
		trio_xstring_append_char((trio_string_t*)self->location, (char)output);
		self->actually.committed++;
	}
	/* The processed variable must always be increased */
	self->processed++;
}


TRIO_PUBLIC int trio_sscanf TRIO_VARGS3((buffer, format, va_alist), TRIO_CONST char* buffer,
                                        TRIO_CONST char* format, TRIO_VA_DECL)
{
	int status;
	va_list args;

	assert(VALID(buffer));
	assert(VALID(format));

	TRIO_VA_START(args, format);
	status =
	    TrioScan((trio_pointer_t)&buffer, 0, TrioInStreamString, NULL, format, args, NULL, NULL);
	TRIO_VA_END(args);
	return status;
}


TRIO_PRIVATE int TrioGetPosition TRIO_ARGS2((format, offsetPointer), TRIO_CONST char* format,
                                            int* offsetPointer)
{
#if TRIO_FEATURE_POSITIONAL
	char* tmpformat;
	int number = 0;
	int offset = *offsetPointer;

	number = (int)trio_to_long(&format[offset], &tmpformat, BASE_DECIMAL);
	offset = (int)(tmpformat - format);
	if ((number != 0) && (QUALIFIER_POSITION == format[offset++]))
	{
		*offsetPointer = offset;
		/*
		 * number is decreased by 1, because n$ starts from 1, whereas
		 * the array it is indexing starts from 0.
		 */
		return number - 1;
	}
#endif
	return NO_POSITION;
}


int trio_get_base TRIO_ARGS1((ref), trio_pointer_t ref)
{
	return (((trio_reference_t*)ref)->parameter->base);
}


TRIO_PUBLIC_STRING int trio_string_equal_case TRIO_ARGS2((self, other), trio_string_t* self,
                                                         trio_string_t* other)
{
	assert(self);
	assert(other);

	return trio_equal_case(self->content, other->content);
}


void trio_set_quote TRIO_ARGS2((ref, is_quote), trio_pointer_t ref, int is_quote)
{
	if (is_quote)
		((trio_reference_t*)ref)->parameter->flags |= FLAGS_QUOTE;
	else
		((trio_reference_t*)ref)->parameter->flags &= ~FLAGS_QUOTE;
}


TRIO_PRIVATE BOOLEAN_T TrioReadDouble TRIO_ARGS4((self, target, flags, width), trio_class_t* self,
                                                 trio_pointer_t target, trio_flags_t flags,
                                                 int width)
{
	int ch;
	char doubleString[512];
	int offset = 0;
	int start;
#if TRIO_FEATURE_QUOTE
	int j;
#endif
	BOOLEAN_T isHex = FALSE;
	trio_long_double_t infinity;

	doubleString[0] = 0;

	if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
		width = sizeof(doubleString) - 1;

	TrioSkipWhitespaces(self);

	/*
	 * Read entire double number from stream. trio_to_double requires
	 * a string as input, but InStream can be anything, so we have to
	 * collect all characters.
	 */
	ch = self->current;
	if ((ch == '+') || (ch == '-'))
	{
		doubleString[offset++] = (char)ch;
		self->InStream(self, &ch);
		width--;
	}

	start = offset;
	switch (ch)
	{
		case 'n':
		case 'N':
			/* Not-a-number */
			if (offset != 0)
				break;
			/* FALLTHROUGH */
		case 'i':
		case 'I':
			/* Infinity */
			while (isalpha(ch) && (offset - start < width))
			{
				doubleString[offset++] = (char)ch;
				self->InStream(self, &ch);
			}
			doubleString[offset] = NIL;

			/* Case insensitive string comparison */
			if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
			    trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
			{
				infinity = ((start == 1) && (doubleString[0] == '-')) ? trio_ninf() : trio_pinf();
				if (!target)
					return FALSE;

				if (flags & FLAGS_LONGDOUBLE)
				{
					*((trio_long_double_t*)target) = infinity;
				}
				else if (flags & FLAGS_LONG)
				{
					*((double*)target) = infinity;
				}
				else
				{
					*((float*)target) = infinity;
				}
				return TRUE;
			}
			if (trio_equal(doubleString, NAN_UPPER))
			{
				if (!target)
					return FALSE;

				/* NaN must not have a preceeding + nor - */
				if (flags & FLAGS_LONGDOUBLE)
				{
					*((trio_long_double_t*)target) = trio_nan();
				}
				else if (flags & FLAGS_LONG)
				{
					*((double*)target) = trio_nan();
				}
				else
				{
					*((float*)target) = trio_nan();
				}
				return TRUE;
			}
			return FALSE;

		case '0':
			doubleString[offset++] = (char)ch;
			self->InStream(self, &ch);
			if (trio_to_upper(ch) == 'X')
			{
				isHex = TRUE;
				doubleString[offset++] = (char)ch;
				self->InStream(self, &ch);
			}
			break;

		default:
			break;
	}

	while ((ch != EOF) && (offset - start < width))
	{
		/* Integer part */
		if (isHex ? isxdigit(ch) : isdigit(ch))
		{
			doubleString[offset++] = (char)ch;
			self->InStream(self, &ch);
		}
#if TRIO_FEATURE_QUOTE
		else if (flags & FLAGS_QUOTE)
		{
			/* Compare with thousands separator */
			for (j = 0; internalThousandSeparator[j] && self->current; j++)
			{
				if (internalThousandSeparator[j] != self->current)
					break;

				self->InStream(self, &ch);
			}
			if (internalThousandSeparator[j])
				break; /* Mismatch */
			else
				continue; /* Match */
		}
#endif
		else
			break; /* while */
	}
	if (ch == '.')
	{
		/* Decimal part */
		doubleString[offset++] = (char)ch;
		self->InStream(self, &ch);
		while ((isHex ? isxdigit(ch) : isdigit(ch)) && (offset - start < width))
		{
			doubleString[offset++] = (char)ch;
			self->InStream(self, &ch);
		}
	}
	if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
	{
		/* Exponent */
		doubleString[offset++] = (char)ch;
		self->InStream(self, &ch);
		if ((ch == '+') || (ch == '-'))
		{
			doubleString[offset++] = (char)ch;
			self->InStream(self, &ch);
		}
		while (isdigit(ch) && (offset - start < width))
		{
			doubleString[offset++] = (char)ch;
			self->InStream(self, &ch);
		}
	}

	if ((offset == start) || (*doubleString == NIL))
		return FALSE;

	doubleString[offset] = 0;

	if (flags & FLAGS_LONGDOUBLE)
	{
		if (!target)
			return FALSE;

		*((trio_long_double_t*)target) = trio_to_long_double(doubleString, NULL);
	}
	else if (flags & FLAGS_LONG)
	{
		if (!target)
			return FALSE;

		*((double*)target) = trio_to_double(doubleString, NULL);
	}
	else
	{
		if (!target)
			return FALSE;

		*((float*)target) = trio_to_float(doubleString, NULL);
	}
	return TRUE;
}


TRIO_PUBLIC_STRING float trio_to_float TRIO_ARGS2((source, endp), TRIO_CONST char* source,
                                                  char** endp)
{
#if defined(USE_STRTOF)
	return strtof(source, endp);
#else
	return (float)trio_to_long_double(source, endp);
#endif
}


void trio_set_sign TRIO_ARGS2((ref, is_sign), trio_pointer_t ref, int is_sign)
{
	if (is_sign)
		((trio_reference_t*)ref)->parameter->flags |= FLAGS_SHOWSIGN;
	else
		((trio_reference_t*)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
}


TRIO_PRIVATE_STRING char* internal_duplicate_max TRIO_ARGS2((source, size), TRIO_CONST char* source,
                                                            size_t size)
{
	char* target;

	assert(source);

	/* Make room for string plus a terminating zero */
	size++;
	target = trio_create(size);
	if (target)
	{
		trio_copy_max(target, size, source);
	}
	return target;
}


TRIO_PUBLIC void trio_locale_set_thousand_separator TRIO_ARGS1((thousandSeparator),
                                                               char* thousandSeparator)
{
#if defined(USE_LOCALE)
	if (NULL == internalLocaleValues)
	{
		TrioSetLocale();
	}
#endif
	trio_copy_max(internalThousandSeparator, sizeof(internalThousandSeparator), thousandSeparator);
	internalThousandSeparatorLength = trio_length(internalThousandSeparator);
}


TRIO_PRIVATE void TrioOutStreamFileDescriptor TRIO_ARGS2((self, output), trio_class_t* self,
                                                         int output)
{
	int fd;
	char ch;

	assert(VALID(self));

	fd = *((int*)self->location);
	ch = (char)output;
	self->processed++;
	if (write(fd, &ch, sizeof(char)) == -1)
	{
		self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
	}
	else
	{
		self->actually.committed++;
	}
}


TRIO_PUBLIC_STRING unsigned long trio_hash TRIO_ARGS2((string, type), TRIO_CONST char* string,
                                                      int type)
{
	unsigned long value = 0L;
	char ch;

	assert(string);

	switch (type)
	{
		case TRIO_HASH_PLAIN:
			while ((ch = *string++) != NIL)
			{
				value *= 31;
				value += (unsigned long)ch;
			}
			break;
		default:
			assert(FALSE);
			break;
	}
	return value;
}


TRIO_PUBLIC_STRING int trio_string_match TRIO_ARGS2((self, other), trio_string_t* self,
                                                    trio_string_t* other)
{
	assert(self);
	assert(other);

	return trio_match(self->content, other->content);
}


TRIO_PUBLIC_STRING int trio_match TRIO_ARGS2((string, pattern), TRIO_CONST char* string,
                                             TRIO_CONST char* pattern)
{
	assert(string);
	assert(pattern);

	for (; ('*' != *pattern); ++pattern, ++string)
	{
		if (NIL == *string)
		{
			return (NIL == *pattern);
		}
		if ((internal_to_upper((int)*string) != internal_to_upper((int)*pattern)) &&
		    ('?' != *pattern))
		{
			return FALSE;
		}
	}
	/* two-line patch to prevent *too* much recursiveness: */
	while ('*' == pattern[1])
		pattern++;

	do
	{
		if (trio_match(string, &pattern[1]))
		{
			return TRUE;
		}
	} while (*string++);

	return FALSE;
}


TRIO_PUBLIC_STRING int trio_equal_case TRIO_ARGS2((first, second), TRIO_CONST char* first,
                                                  TRIO_CONST char* second)
{
	assert(first);
	assert(second);

	if ((first != NULL) && (second != NULL))
	{
		return (0 == strcmp(first, second));
	}
	return FALSE;
}


TRIO_PUBLIC_STRING int trio_string_contains TRIO_ARGS2((self, other), trio_string_t* self,
                                                       trio_string_t* other)
{
	assert(self);
	assert(other);

	return trio_contains(self->content, other->content);
}


int trio_get_size TRIO_ARGS1((ref), trio_pointer_t ref)
{
	return (((trio_reference_t*)ref)->parameter->flags & FLAGS_SIZE_T) ? TRUE : FALSE;
}


TRIO_PUBLIC_STRING int trio_string_size TRIO_ARGS1((self), trio_string_t* self)
{
	assert(self);

	return self->allocated;
}


TRIO_PRIVATE int TrioReadChar TRIO_ARGS4((self, target, flags, width), trio_class_t* self,
                                         char* target, trio_flags_t flags, int width)
{
	int i;
	char ch;
	trio_uintmax_t number;

	assert(VALID(self));
	assert(VALID(self->InStream));

	for (i = 0; (self->current != EOF) && (i < width); i++)
	{
		ch = (char)self->current;
		self->InStream(self, NULL);
		if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
		{
			switch (self->current)
			{
				case '\\':
					ch = '\\';
					break;
				case 'a':
					ch = '\007';
					break;
				case 'b':
					ch = '\b';
					break;
				case 'f':
					ch = '\f';
					break;
				case 'n':
					ch = '\n';
					break;
				case 'r':
					ch = '\r';
					break;
				case 't':
					ch = '\t';
					break;
				case 'v':
					ch = '\v';
					break;
				default:
					if (isdigit(self->current))
					{
						/* Read octal number */
						if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
							return 0;
						ch = (char)number;
					}
					else if (trio_to_upper(self->current) == 'X')
					{
						/* Read hexadecimal number */
						self->InStream(self, NULL);
						if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
							return 0;
						ch = (char)number;
					}
					else
					{
						ch = (char)self->current;
					}
					break;
			}
		}

		if (target)
			target[i] = ch;
	}
	return i + 1;
}


TRIO_PUBLIC int trio_scanf TRIO_VARGS2((format, va_alist), TRIO_CONST char* format, TRIO_VA_DECL)
{
	int status;
	va_list args;

	assert(VALID(format));

	TRIO_VA_START(args, format);
	status = TrioScan((trio_pointer_t)stdin, 0, TrioInStreamFile, TrioUndoStreamFile, format, args,
	                  NULL, NULL);
	TRIO_VA_END(args);
	return status;
}


int trio_get_width TRIO_ARGS1((ref), trio_pointer_t ref)
{
	return ((trio_reference_t*)ref)->parameter->width;
}


static trio_pointer_t TrioArrayGetter(trio_pointer_t context, int index, int type)
{
	/* Utility function for the printfv family */
	trio_pointer_t* argarray = (trio_pointer_t*)context;
	return argarray[index];
}


TRIO_PUBLIC_STRING int trio_equal TRIO_ARGS2((first, second), TRIO_CONST char* first,
                                             TRIO_CONST char* second)
{
	assert(first);
	assert(second);

	if ((first != NULL) && (second != NULL))
	{
#if defined(USE_STRCASECMP)
		return (0 == strcasecmp(first, second));
#else
		while ((*first != NIL) && (*second != NIL))
		{
			if (internal_to_upper(*first) != internal_to_upper(*second))
			{
				break;
			}
			first++;
			second++;
		}
		return ((*first == NIL) && (*second == NIL));
#endif
	}
	return FALSE;
}


TRIO_PUBLIC_STRING int trio_xstring_contains TRIO_ARGS2((self, other), trio_string_t* self,
                                                        TRIO_CONST char* other)
{
	assert(self);
	assert(other);

	return trio_contains(self->content, other);
}


TRIO_PUBLIC int trio_vdprintf TRIO_ARGS3((fd, format, args), int fd, TRIO_CONST char* format,
                                         va_list args)
{
	assert(VALID(format));

	return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL, NULL);
}


TRIO_PUBLIC int trio_dscanf TRIO_VARGS3((fd, format, va_alist), int fd, TRIO_CONST char* format,
                                        TRIO_VA_DECL)
{
	int status;
	va_list args;

	assert(VALID(format));

	TRIO_VA_START(args, format);
	status = TrioScan((trio_pointer_t)&fd, 0, TrioInStreamFileDescriptor, NULL, format, args, NULL,
	                  NULL);
	TRIO_VA_END(args);
	return status;
}


static void license_print_product_info(const LICENSE_PRODUCT_INFO* productInfo)
{
	char* CompanyName = NULL;
	char* ProductId = NULL;
	ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)productInfo->pbCompanyName,
	                   productInfo->cbCompanyName / 2, &CompanyName, 0, NULL, NULL);
	ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)productInfo->pbProductId, productInfo->cbProductId / 2,
	                   &ProductId, 0, NULL, NULL);
	WLog_INFO(TAG, "ProductInfo:");
	WLog_INFO(TAG, "\tdwVersion: 0x%08" PRIX32 "", productInfo->dwVersion);
	WLog_INFO(TAG, "\tCompanyName: %s", CompanyName);
	WLog_INFO(TAG, "\tProductId: %s", ProductId);
	free(CompanyName);
	free(ProductId);
}


rdpLicense* license_new(rdpRdp* rdp)
{
	rdpLicense* license;
	license = (rdpLicense*)calloc(1, sizeof(rdpLicense));
	if (!license)
		return NULL;

	license->rdp = rdp;
	license->state = LICENSE_STATE_AWAIT;
	if (!(license->certificate = certificate_new()))
		goto out_error;
	if (!(license->ProductInfo = license_new_product_info()))
		goto out_error;
	if (!(license->ErrorInfo = license_new_binary_blob(BB_ERROR_BLOB)))
		goto out_error;
	if (!(license->KeyExchangeList = license_new_binary_blob(BB_KEY_EXCHG_ALG_BLOB)))
		goto out_error;
	if (!(license->ServerCertificate = license_new_binary_blob(BB_CERTIFICATE_BLOB)))
		goto out_error;
	if (!(license->ClientUserName = license_new_binary_blob(BB_CLIENT_USER_NAME_BLOB)))
		goto out_error;
	if (!(license->ClientMachineName = license_new_binary_blob(BB_CLIENT_MACHINE_NAME_BLOB)))
		goto out_error;
	if (!(license->PlatformChallenge = license_new_binary_blob(BB_ANY_BLOB)))
		goto out_error;
	if (!(license->EncryptedPlatformChallenge = license_new_binary_blob(BB_ANY_BLOB)))
		goto out_error;
	if (!(license->EncryptedPlatformChallengeResponse =
	          license_new_binary_blob(BB_ENCRYPTED_DATA_BLOB)))
		goto out_error;
	if (!(license->EncryptedPremasterSecret = license_new_binary_blob(BB_ANY_BLOB)))
		goto out_error;
	if (!(license->EncryptedHardwareId = license_new_binary_blob(BB_ENCRYPTED_DATA_BLOB)))
		goto out_error;
	if (!(license->ScopeList = license_new_scope_list()))
		goto out_error;

	license_generate_randoms(license);

	return license;

out_error:
	license_free(license);
	return NULL;
}


PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
{
	return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
}


rrinternal_get_ttl(sldns_buffer* strbuf, char* token, size_t token_len,
	int* not_there, uint32_t* ttl, uint32_t default_ttl)
{
	const char* endptr;
	if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
		return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TTL,
			sldns_buffer_position(strbuf));
	}
	*ttl = (uint32_t) sldns_str2period(token, &endptr);

	if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) {
		*not_there = 1;
		/* ah, it's not there or something */
		if (default_ttl == 0) {
			*ttl = LDNS_DEFAULT_TTL;
		} else {
			*ttl = default_ttl;
		}
	}
	return LDNS_WIREPARSE_ERR_OK;
}


int sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len,
	size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
	size_t origin_len, uint8_t* prev, size_t prev_len)
{
	return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len,
		default_ttl, origin, origin_len, prev, prev_len, 0);
}


int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
    cmsHTRANSFORM xform;
    cmsUInt32Number i, nColors, nColorant;
    cmsUInt32Number OutputFormat;
    char ColorName[cmsMAX_PATH];
    char Colorant[512];
    cmsNAMEDCOLORLIST* NamedColorList;

    OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE);
    nColorant    = T_CHANNELS(OutputFormat);

    xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags);
    if (xform == NULL) return 0;

    NamedColorList = cmsGetNamedColorList(xform);
    if (NamedColorList == NULL) return 0;

    _cmsIOPrintf(m, "<<\n");
    _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
    _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
    _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");

    nColors   = cmsNamedColorCount(NamedColorList);

    for (i=0; i < nColors; i++) {

        cmsUInt16Number In[1];
        cmsUInt16Number Out[cmsMAXCHANNELS];

        In[0] = (cmsUInt16Number) i;

        if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
                continue;

        cmsDoTransform(xform, In, Out, 1);
        BuildColorantList(Colorant, nColorant, Out);
        _cmsIOPrintf(m, "  (%s) [ %s ]\n", ColorName, Colorant);
    }

    _cmsIOPrintf(m, "   >>");

    if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {

    _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n");
    }

    cmsDeleteTransform(xform);
    return 1;
}


mp_sint32 PlayerGeneric::getTempo() const
{
	if (player)
	{
		mp_uint32 index = player->getBeatIndexFromSamplePos(getCurrentSamplePosition());
		return player->getTempo(index);
	}

	return 0;
}


camel_stream_buffer_class_init (CamelStreamBufferClass *class)
{
	GObjectClass *object_class;
	CamelStreamClass *stream_class;

	object_class = G_OBJECT_CLASS (class);
	object_class->dispose = stream_buffer_dispose;
	object_class->finalize = stream_buffer_finalize;

	stream_class = CAMEL_STREAM_CLASS (class);
	stream_class->read = stream_buffer_read;
	stream_class->write = stream_buffer_write;
	stream_class->flush = stream_buffer_flush;
	stream_class->close = stream_buffer_close;
	stream_class->eos = stream_buffer_eos;

	class->init = stream_buffer_init_method;
}


smtp_decode_status_code (const gchar *in,
                         gsize len)
{
	guchar *inptr, *outptr;
	const guchar *inend;
	gchar *outbuf;

	outbuf = (gchar *) g_malloc (len + 1);
	outptr = (guchar *) outbuf;

	inptr = (guchar *) in;
	inend = inptr + len;
	while (inptr < inend) {
		if (*inptr == '+') {
			if (isxdigit (inptr[1]) && isxdigit (inptr[2])) {
				*outptr++ = HEXVAL (inptr[1]) * 16 + HEXVAL (inptr[2]);
				inptr += 3;
			} else
				*outptr++ = *inptr++;
		} else
			*outptr++ = *inptr++;
	}

	*outptr = '\0';

	return outbuf;
}


camel_pop3_stream_class_init (CamelPOP3StreamClass *class)
{
	GObjectClass *object_class;
	CamelStreamClass *stream_class;

	object_class = G_OBJECT_CLASS (class);
	object_class->dispose = pop3_stream_dispose;
	object_class->finalize = pop3_stream_finalize;

	stream_class = CAMEL_STREAM_CLASS (class);
	stream_class->read = stream_read;
	stream_class->write = stream_write;
	stream_class->close = stream_close;
	stream_class->flush = stream_flush;
	stream_class->eos = stream_eos;
}


smtp_transport_send_to_sync (CamelTransport *transport,
                             CamelMimeMessage *message,
                             CamelAddress *from,
                             CamelAddress *recipients,
			     gboolean *out_sent_message_saved,
                             GCancellable *cancellable,
                             GError **error)
{
	CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (transport);
	CamelInternetAddress *cia;
	CamelStreamBuffer *istream;
	CamelStream *ostream;
	gboolean has_8bit_parts = FALSE;
	const gchar *addr;
	gint i, len;

	smtp_debug_print_server_name (CAMEL_SERVICE (transport), "Sending with");

	istream = smtp_ref_istream (smtp_transport);
	ostream = smtp_ref_ostream (smtp_transport);

	if (!smtp_transport->connected || !istream || !ostream) {
		g_clear_object (&istream);
		g_clear_object (&ostream);
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_NOT_CONNECTED,
			_("Cannot send message: service not connected."));
		return FALSE;
	}

	if (!camel_internet_address_get (CAMEL_INTERNET_ADDRESS (from), 0, NULL, &addr)) {
		g_clear_object (&istream);
		g_clear_object (&ostream);
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Cannot send message: sender address not valid."));
		return FALSE;
	}

	camel_operation_push_message (cancellable, _("Sending message"));

	/* find out if the message has 8bit mime parts; quoted-printable are reencoded to 8bit too */
	camel_mime_message_foreach_part (message, message_has_8bit_or_qp_part_cb, &has_8bit_parts);

	/* If the connection needs a ReSET, then do so */
	if (smtp_transport->need_rset &&
	    !smtp_rset (smtp_transport, istream, ostream, cancellable, error)) {
		camel_operation_pop_message (cancellable);
		g_clear_object (&istream);
		g_clear_object (&ostream);
		return FALSE;
	}
	smtp_transport->need_rset = FALSE;

	/* rfc1652 (8BITMIME) requires that you notify the ESMTP daemon that
	 * you'll be sending an 8bit mime message at "MAIL FROM:" time. */
	if (!smtp_mail (
		smtp_transport, istream, ostream, addr, has_8bit_parts, cancellable, error)) {
		camel_operation_pop_message (cancellable);
		g_clear_object (&istream);
		g_clear_object (&ostream);
		return FALSE;
	}

	len = camel_address_length (recipients);
	if (len == 0) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Cannot send message: no recipients defined."));
		camel_operation_pop_message (cancellable);
		smtp_transport->need_rset = TRUE;
		g_clear_object (&istream);
		g_clear_object (&ostream);
		return FALSE;
	}

	cia = CAMEL_INTERNET_ADDRESS (recipients);
	for (i = 0; i < len; i++) {
		gchar *enc;

		if (!camel_internet_address_get (cia, i, NULL, &addr)) {
			g_set_error (
				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
				_("Cannot send message: "
				"one or more invalid recipients"));
			camel_operation_pop_message (cancellable);
			smtp_transport->need_rset = TRUE;
			g_clear_object (&istream);
			g_clear_object (&ostream);
			return FALSE;
		}

		enc = camel_internet_address_encode_address (NULL, NULL, addr);
		if (!smtp_rcpt (smtp_transport, istream, ostream, enc, cancellable, error)) {
			g_free (enc);
			camel_operation_pop_message (cancellable);
			smtp_transport->need_rset = TRUE;
			g_clear_object (&istream);
			g_clear_object (&ostream);
			return FALSE;
		}
		g_free (enc);
	}

	if (!smtp_data (smtp_transport, istream, ostream, message, cancellable, error)) {
		camel_operation_pop_message (cancellable);
		smtp_transport->need_rset = TRUE;
		g_clear_object (&istream);
		g_clear_object (&ostream);
		return FALSE;
	}

	camel_operation_pop_message (cancellable);
	g_clear_object (&istream);
	g_clear_object (&ostream);

	return TRUE;
}


camel_smtp_transport_init (CamelSmtpTransport *smtp)
{
	smtp->flags = 0;
	smtp->connected = FALSE;

	g_mutex_init (&smtp->stream_lock);
}


authtypes_free (gpointer key,
                gpointer value,
                gpointer data)
{
	g_free (value);
}


pop3_store_get_property (GObject *object,
                         guint property_id,
                         GValue *value,
                         GParamSpec *pspec)
{
	switch (property_id) {
		case PROP_CONNECTABLE:
			g_value_take_object (
				value,
				camel_network_service_ref_connectable (
				CAMEL_NETWORK_SERVICE (object)));
			return;

		case PROP_HOST_REACHABLE:
			g_value_set_boolean (
				value,
				camel_network_service_get_host_reachable (
				CAMEL_NETWORK_SERVICE (object)));
			return;
	}

	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}


camel_pop3_store_cache_has (CamelPOP3Store *store,
                            const gchar *uid)
{
	CamelStream *stream;
	gboolean uid_is_cached;

	g_return_val_if_fail (CAMEL_IS_POP3_STORE (store), FALSE);
	g_return_val_if_fail (uid != NULL, FALSE);

	stream = camel_pop3_store_cache_get (store, uid, NULL);
	uid_is_cached = (stream != NULL);
	g_clear_object (&stream);

	return uid_is_cached;
}


smtp_transport_get_property (GObject *object,
                             guint property_id,
                             GValue *value,
                             GParamSpec *pspec)
{
	switch (property_id) {
		case PROP_CONNECTABLE:
			g_value_take_object (
				value,
				camel_network_service_ref_connectable (
				CAMEL_NETWORK_SERVICE (object)));
			return;

		case PROP_HOST_REACHABLE:
			g_value_set_boolean (
				value,
				camel_network_service_get_host_reachable (
				CAMEL_NETWORK_SERVICE (object)));
			return;
	}

	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}


blobGetDataSize(const blob *b)
{
    assert(b != NULL);
#ifdef CL_DEBUG
    assert(b->magic == BLOBCLASS);
#endif

    return b->len;
}