Exemplo n.º 1
0
static void
raise_ZipError(YogEnv* env, YogVal pkg, const char* msg)
{
    SAVE_ARG(env, pkg);
    YogVal eZipError = YUNDEF;
    YogVal e = YUNDEF;
    YogVal s = YUNDEF;
    PUSH_LOCALS3(env, eZipError, e, s);
    if (!IS_PTR(pkg) || (BASIC_OBJ_TYPE(pkg) != TYPE_ZIP_PKG)) {
        YogError_raise_TypeError(env, "package type must be TYPE_ZIP_PKG");
    }

    eZipError = PTR_AS(Package, pkg)->eZipError;
    if (msg != NULL) {
        s = YogString_from_string(env, msg);
        e = YogEval_call_method1(env, eZipError, "new", s);
    }
    else {
        e = YogEval_call_method0(env, eZipError, "new");
    }
    YogError_raise(env, e);
    /* NOTREACHED */

    RETURN_VOID(env);
}
Exemplo n.º 2
0
static void
exec_get_attr(YogEnv* env, YogVal self, ID name)
{
    SAVE_ARG(env, self);
    YogVal klass = YUNDEF;
    YogVal attr = YUNDEF;
    PUSH_LOCALS2(env, klass, attr);

    klass = YogVal_get_class(env, self);
    attr = YogClass_get_attr(env, klass, name);
    if (!IS_UNDEF(attr)) {
        attr = YogVal_get_descr(env, attr, self, klass);
        YogScriptFrame_push_stack(env, env->frame, attr);
        RETURN_VOID(env);
    }

    attr = YogObj_get_attr(env, self, name);
    if (!IS_UNDEF(attr)) {
        attr = YogVal_get_descr(env, attr, YNIL, self);
        YogScriptFrame_push_stack(env, env->frame, attr);
        RETURN_VOID(env);
    }

    YogError_raise_AttributeError(env, "%C object has no attribute \"%I\"", self, name);

    /* NOTREACHED */
    RETURN_VOID(env);
}
Exemplo n.º 3
0
void
YogVM_remove_thread(YogEnv* env, YogVM* vm, YogVal thread)
{
    SAVE_ARG(env, thread);

    YogVM_acquire_global_interp_lock(env, vm);
    gc(env, vm);

    YogVal prev = PTR_AS(YogThread, thread)->prev;
    YogVal next = PTR_AS(YogThread, thread)->next;
    if (IS_PTR(prev)) {
        YogGC_UPDATE_PTR(env, PTR_AS(YogThread, prev), next, next);
    }
    else {
        vm->running_threads = next;
    }
    if (IS_PTR(next)) {
        YogGC_UPDATE_PTR(env, PTR_AS(YogThread, next), prev, prev);
    }

    if (!IS_PTR(vm->running_threads)) {
        pthread_cond_signal(&vm->vm_finish_cond);
    }

    RESTORE_LOCALS(env);

    YogVM_release_global_interp_lock(env, vm);
}
Exemplo n.º 4
0
ID
YogVM_intern2(YogEnv* env, YogVM* vm, YogVal name)
{
    SAVE_ARG(env, name);
    YogVal value = YUNDEF;
    PUSH_LOCAL(env, value);

#define FIND_SYM do { \
    if (YogTable_lookup(env, vm->name2id, name, &value)) { \
        release_symbols_lock(env, vm); \
        RETURN(env, VAL2ID(value)); \
    } \
} while (0)
    acquire_symbols_read_lock(env, vm);
    FIND_SYM;
    release_symbols_lock(env, vm);

    acquire_symbols_write_lock(env, vm);
    FIND_SYM;
#undef FIND_SYM

    YogHandle* clone = VAL2HDL(env, YogString_clone(env, name));
    ID id = vm->next_id;
    YogVal symbol = ID2VAL(id);
    YogTable_add_direct(env, vm->name2id, HDL2VAL(clone), symbol);
    YogTable_add_direct(env, vm->id2name, symbol, HDL2VAL(clone));
    vm->next_id++;

    release_symbols_lock(env, vm);
    RETURN(env, id);
}
Exemplo n.º 5
0
void
YogRegexp_define_classes(YogEnv* env, YogVal pkg)
{
    SAVE_ARG(env, pkg);
    YogVal cRegexp = YUNDEF;
    YogVal cMatch = YUNDEF;
    PUSH_LOCALS2(env, cRegexp, cMatch);
    YogVM* vm = env->vm;

    cRegexp = YogClass_new(env, "Regexp", vm->cObject);
#define DEFINE_METHOD(name, ...) do { \
    YogClass_define_method2(env, cRegexp, pkg, (name), __VA_ARGS__); \
} while (0)
    DEFINE_METHOD("match", match, "s", "|", "pos", NULL);
    DEFINE_METHOD("search", search, "s", "|", "pos", NULL);
#undef DEFINE_METHOD
    vm->cRegexp = cRegexp;

    cMatch = YogClass_new(env, "Match", vm->cObject);
#define DEFINE_METHOD(name, f)  do { \
    YogClass_define_method(env, cMatch, pkg, (name), (f)); \
} while (0)
    DEFINE_METHOD("start", start);
    DEFINE_METHOD("end", end);
#undef DEFINE_METHOD
#define DEFINE_METHOD2(name, ...) do { \
    YogClass_define_method2(env, cMatch, pkg, (name), __VA_ARGS__); \
} while (0)
    DEFINE_METHOD2("group", group, "|", "group", NULL);
#undef DEFINE_METHOD2
    vm->cMatch = cMatch;

    RETURN_VOID(env);
}
Exemplo n.º 6
0
static void
raise_invalid_group(YogEnv* env, YogVal group)
{
    SAVE_ARG(env, group);
    YogError_raise_TypeError(env, "group must be a Fixnum, String or nil, not %C", group);
    /* NOTREACHED */
    RETURN_VOID(env);
}
Exemplo n.º 7
0
static void
close_zip(YogEnv* env, YogVal pkg, struct zip* archive)
{
    SAVE_ARG(env, pkg);
    if (zip_close(archive) != 0) {
        raise_ZipError(env, pkg, zip_strerror(archive));
    }
    RETURN_VOID(env);
}
Exemplo n.º 8
0
YogVal
YogClass_alloc(YogEnv* env, YogVal klass)
{
    SAVE_ARG(env, klass);
    YogVal obj = YUNDEF;
    PUSH_LOCAL(env, obj);

    obj = ALLOC_OBJ(env, YogClass_keep_children, NULL, YogClass);
    YogClass_init(env, obj, TYPE_CLASS, klass);

    RETURN(env, obj);
}
Exemplo n.º 9
0
static void
register_encoding(YogEnv* env, YogVM* vm, const char* name, YogVal enc)
{
    SAVE_ARG(env, enc);
    YogVal s = YUNDEF;
    PUSH_LOCAL(env, s);

    s = YogString_from_string(env, name);
    YogDict_set(env, vm->encodings, s, enc);

    RETURN_VOID(env);
}
Exemplo n.º 10
0
void
YogEnumerable_define_classes(YogEnv* env, YogVal pkg)
{
    SAVE_ARG(env, pkg);
    YogVal mEnumerable = YUNDEF;
    PUSH_LOCAL(env, mEnumerable);
    YogVM* vm = env->vm;

    mEnumerable = YogModule_of_name(env, "Enumerable");
    vm->mEnumerable = mEnumerable;

    RETURN_VOID(env);
}
Exemplo n.º 11
0
YogVal
YogClass_new(YogEnv* env, const char* name, YogVal super)
{
    SAVE_ARG(env, super);
    YogVal obj = YUNDEF;
    PUSH_LOCAL(env, obj);

    obj = YogClass_alloc(env, env->vm->cClass);
    YogGC_UPDATE_PTR(env, PTR_AS(YogClass, obj), super, super);
    ID id = name == NULL ? INVALID_ID : YogVM_intern(env, env->vm, name);
    PTR_AS(YogClass, obj)->name = id;

    RETURN(env, obj);
}
Exemplo n.º 12
0
static void
wait_package(YogEnv* env, YogVal pkg)
{
    SAVE_ARG(env, pkg);

    pthread_cond_t* cond = &PTR_AS(ImportingPackage, pkg)->cond;
    pthread_mutex_t* lock = &PTR_AS(ImportingPackage, pkg)->lock;
    while (!IS_PTR(PTR_AS(ImportingPackage, pkg)->pkg)) {
        YogGC_free_from_gc(env);
        pthread_cond_wait(cond, lock);
        YogGC_bind_to_gc(env);
    }

    RETURN_VOID(env);
}
Exemplo n.º 13
0
void
YogEncoding_define_classes(YogEnv* env, YogVal pkg)
{
    SAVE_ARG(env, pkg);
    YogVal cEncoding = YUNDEF;
    PUSH_LOCAL(env, cEncoding);
    YogVM* vm = env->vm;

    cEncoding = YogClass_new(env, "Encoding", vm->cObject);
    YogClass_define_allocator(env, cEncoding, alloc);
    YogClass_define_method(env, cEncoding, pkg, "create_string", create_string);
    vm->cEncoding = cEncoding;

    RETURN_VOID(env);
}
Exemplo n.º 14
0
void
YogVM_add_thread(YogEnv* env, YogVM* vm, YogVal thread)
{
    SAVE_ARG(env, thread);

    YogVM_acquire_global_interp_lock(env, vm);
    gc(env, vm);

    YogGC_UPDATE_PTR(env, PTR_AS(YogThread, vm->running_threads), prev, thread);
    YogGC_UPDATE_PTR(env, PTR_AS(YogThread, thread), next, vm->running_threads);
    vm->running_threads = thread;

    YogVM_release_global_interp_lock(env, vm);

    RETURN_VOID(env);
}
Exemplo n.º 15
0
void
YogProperty_define_classes(YogEnv* env, YogVal pkg)
{
    SAVE_ARG(env, pkg);
    YogVal cProperty = YUNDEF;
    PUSH_LOCAL(env, cProperty);
    YogVM* vm = env->vm;

    cProperty = YogClass_new(env, "Property", vm->cObject);
    YogClass_define_descr_get_executor(env, cProperty, exec_get_descr);
    YogClass_define_descr_get_caller(env, cProperty, call_get_descr);
    YogClass_define_descr_set_executor(env, cProperty, exec_set_descr);
    vm->cProperty = cProperty;

    RETURN_VOID(env);
}
Exemplo n.º 16
0
static void
setup_classes(YogEnv* env, YogVM* vm, YogVal builtins)
{
    SAVE_ARG(env, builtins);

    YogProperty_define_classes(env, builtins);
    YogFunction_define_classes(env, builtins);

    YogObj_class_init(env, vm->cObject, builtins);
    YogClass_class_init(env, vm->cClass, builtins);

    YogComparable_define_classes(env, builtins);
    YogEnumerable_define_classes(env, builtins);
    YogString_define_classes(env, builtins);

    YogHandle* h_builtins = YogHandle_REGISTER(env, builtins);

    YogArray_define_classes(env, builtins);
    YogBignum_define_classes(env, builtins);
    YogBinary_define_classes(env, builtins);
    YogBool_define_classes(env, builtins);
    YogClassMethod_define_classes(env, builtins);
    YogCode_define_classes(env, h_builtins);
    YogCoroutine_define_classes(env, builtins);
    YogDatetime_define_classes(env, h_builtins);
    YogDict_define_classes(env, builtins);
    YogDir_define_classes(env, h_builtins);
    YogEncoding_define_classes(env, builtins);
    YogEnv_define_classes(env, h_builtins);
    YogFFI_define_classes(env, builtins);
    YogFile_define_classes(env, builtins);
    YogFixnum_define_classes(env, builtins);
    YogFloat_define_classes(env, builtins);
    YogModule_define_classes(env, builtins);
    YogNil_define_classes(env, builtins);
    YogPackage_define_classes(env, builtins);
    YogPath_define_classes(env, h_builtins);
    YogProcess_define_classes(env, h_builtins);
    YogRegexp_define_classes(env, builtins);
    YogSet_define_classes(env, builtins);
    YogStat_define_classes(env, h_builtins);
    YogSymbol_define_classes(env, builtins);
    YogThread_define_classes(env, builtins);

    RETURN_VOID(env);
}
Exemplo n.º 17
0
static YogVal
call_get_attr(YogEnv* env, YogVal self, ID name)
{
    SAVE_ARG(env, self);
    YogVal klass = YUNDEF;
    YogVal attr = YUNDEF;
    PUSH_LOCALS2(env, klass, attr);

    klass = YogVal_get_class(env, self);
    attr = YogClass_get_attr(env, klass, name);
    if (!IS_UNDEF(attr)) {
        attr = YogVal_get_descr(env, attr, self, klass);
        RETURN(env, attr);
    }

    attr = YogObj_get_attr(env, self, name);
    if (!IS_UNDEF(attr)) {
        attr = YogVal_get_descr(env, attr, YNIL, self);
        RETURN(env, attr);
    }

    RETURN(env, YUNDEF);
}
Exemplo n.º 18
0
/* Parse a string of one of the forms:
 *	    "domain[,[any][,bltype]]
 *	    "domain[,[IPaddr[&IPmask]][,bltype]]
 *	    "domain[,[IPaddr[/xx][&IPmask]][,bltype]]
 *	    "domain[,[IPaddrLO-IPaddrHI[&IPmask]][,name|ipv4|ipv6]]
 *		where bltype is "name", "all-names", "IPv4", or "IPv6"
 *
 *	    set:[no-]client	client IP address checks
 *	    set:[no-]mail_host	envelope mail_from checks
 *	    set:[no-]URL	body URL checks
 *	    set:[no-]MX		MX checks
 *	    set:[no-]NS		NS checks
 *	    set:white		DNS whitelist
 *	    set:black		DNS blacklist
 *	    set:defaults	restore defaults
 *	    set:group=X		start group of lists
 *	    set:debug=X		more logging
 *	    set:msg-secs=S	total seconds checking blacklists/message
 *	    set:url-secs=S	total seconds per host name
 *
 *	    set:rej-msg="rejection message"
 *	    set:progpath	path of helper program
 *	    set:max_helpers=X	override dccm or dccifd max_work
 *
 *	    set:[no-]body	body URL checks
 *	    set:[no-]envelope	obsolete mail host and client
 *
 *	    set:helper=soc,fd,X	start DNS resolver process
 */
u_char					/* 0=bad */
dcc_parse_dnsbl(DCC_EMSG emsg, const char *entry, const char *progpath)
{
	DNSBL *dp1, **dpp;
	const char *tgt_ip_start;
	char tgt_ip_buf[INET6_ADDRSTRLEN*3+10];
	DNSBL_TYPE type;
	int dom_len, tgt_ip_len;
	char *p;
	int val;
	u_char seen_dp;
#ifdef HAVE_HELPERS
	int soc;
	int fd;
	int total_helpers;
#	define SAVE_ARG(arg) helper_save_arg("-B", arg)
#else
#	define SAVE_ARG(arg)
#endif

	if (progpath && dnsbl_progpath[0] == '\0') {
		const char *slash = strrchr(progpath, '/');
		if (slash)
			++slash;
		else
			slash = progpath;
		snprintf(dnsbl_progpath, sizeof(dnsbl_progpath),
			 "%.*sdns-helper", (int)(slash-progpath), progpath);
	}

	/* handle parameter settings */
	if (!CLITCMP(entry, "set:")) {
		const char *parm = entry+LITZ("set:");
#ifdef HAVE_HELPERS
		/* start running a helper process on the last, magic -B */
		if (3 == sscanf(parm, HELPER_PAT, &soc, &fd, &total_helpers)) {
			helper_child(soc, fd, total_helpers);
		}
#endif
		if (!strcasecmp(parm, "client")) {
			parse_tgts |= DNSBL_HIT_CLIENT;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "no-client")) {
			parse_tgts &= ~DNSBL_HIT_CLIENT;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "mail_host")
		    || !strcasecmp(parm, "mail-host")) {
			parse_tgts |= DNSBL_HIT_MHOST;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "no-mail_host")
		    || !strcasecmp(parm, "no-mail-host")) {
			parse_tgts &= ~DNSBL_HIT_MHOST;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "url")) {
			parse_tgts |= DNSBL_HIT_URL;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "no-URL")) {
			parse_tgts &= ~DNSBL_HIT_URL;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "mx")) {
#ifdef MXNS_DNSBL
			parse_mx_ok = 1;
			SAVE_ARG(entry);
			return 1;
#else
			dcc_pemsg(EX_USAGE, emsg,
				  "MX DNS blacklist checks"
				  " not supported on "DCC_TARGET_SYS);
			return 0;
#endif
		}
		if (!strcasecmp(parm, "no-mx")) {
			parse_mx_ok = 0;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "ns")) {
#ifdef MXNS_DNSBL
			parse_ns_ok = 1;
			SAVE_ARG(entry);
			return 1;
#else
			dcc_pemsg(EX_USAGE, emsg,
				  "NS DNS blacklist checks"
				  " not supported on "DCC_TARGET_SYS);
			return 0;
#endif
		}
		if (!strcasecmp(parm, "no-ns")) {
			parse_ns_ok = 0;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "white")) {
			parse_tgts |= DNSBL_HIT_WHITE;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "black")) {
			parse_tgts &= ~DNSBL_HIT_WHITE;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "defaults")) {
			parse_tgts = DNSBL_HIT_SRCS;
			parse_mx_ok = 1;
			parse_ns_ok = 1;
			parse_reply = 0;
			SAVE_ARG(entry);
			return 1;
		}
		if (!CLITCMP(parm, "rej-msg=")) {
			parm += LITZ("rej-msg=");
			if (*parm == '\0')
				parse_reply = 0;
			else
				parse_reply = dnsbl_parse_reply(parm);
			/* do not save for helpers */
			return 1;
		}
		if (!CLITCMP(parm, "msg-secs=")) {
			parm += LITZ("msg-secs=");
			val = strtoul(parm, &p, 10);
			if (*p != '\0'
			    || val < MIN_MSG_SECS || val > MAX_MSG_SECS) {
				dcc_pemsg(EX_USAGE, emsg,
					  "bad number of seconds in \"-B %s\"",
					  entry);
				return 0;
			}
			if (msg_secs != val) {
				msg_secs = val;
				SAVE_ARG(entry);
			}
			return 1;
		}
		if (!CLITCMP(parm, "url-secs=")) {
			parm += LITZ("url-secs=");
			val = strtoul(parm, &p, 10);
			if (*p != '\0'
			    || val < MIN_URL_SECS || val > MAX_MSG_SECS) {
				dcc_pemsg(EX_USAGE, emsg,
					  "bad number of seconds in \"-B %s\"",
					  entry);
				return 0;
			}
			if (url_secs != val) {
				url_secs = val;
				SAVE_ARG(entry);
			}
			return 1;
		}
		if (1 == sscanf(parm, "group=%d", &val)
		    && val >= 1 && val <= NUM_DNSBL_GROUPS) {
			parse_gnum = val-1;
			have_dnsbl_groups = 1;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "debug")) {
			++helper.debug;
			SAVE_ARG(entry);
			return 1;
		}
		if (1 == sscanf(parm, "debug=%d", &val)) {
			helper.debug = val;
			SAVE_ARG(entry);
			return 1;
		}
		if (!CLITCMP(parm, "progpath=")) {
			BUFCPY(dnsbl_progpath, parm+LITZ("progpath="));
			return 1;
		}
		if (1 == sscanf(parm, "max_helpers=%d", &val)
		    && val >= 1 && val < 1000) {
			helper.max_helpers = val;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "body")) {    /* obsolete */
			parse_tgts |= DNSBL_HIT_URL;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "no-body")) { /* obsolete */
			parse_tgts &= ~DNSBL_HIT_URL;
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "envelope")) {	/* obsolete */
			parse_tgts |= (DNSBL_HIT_CLIENT | DNSBL_HIT_MHOST);
			SAVE_ARG(entry);
			return 1;
		}
		if (!strcasecmp(parm, "no-envelope")) {	/* obsolete */
			parse_tgts &= ~(DNSBL_HIT_CLIENT | DNSBL_HIT_MHOST);
			SAVE_ARG(entry);
			return 1;
		}
		dcc_pemsg(EX_USAGE, emsg, "unrecognized  \"-B %s\"",
			  entry);
		return 0;
	}

	/* we have a DNSDBL specification instead of an option setting */
	if (!parse_dp)
		parse_dp = dcc_malloc(sizeof(*parse_dp));
	memset(parse_dp, 0, sizeof(*parse_dp));
	type = DNSBL_TYPE_IPV4;		/* assume it is a simple IPv4 list */
	tgt_ip_start = strchr(entry, ',');
	if (!tgt_ip_start) {
		dom_len = strlen(entry);
		have_ipv4_dnsbl = 1;
		tgt_ip_len = 0;
	} else {
		dom_len = tgt_ip_start - entry;
		++tgt_ip_start;

		/* notice trailing ",name" or ",IPv4" */
		p = strchr(tgt_ip_start, ',');
		if (!p) {
			tgt_ip_len = strlen(tgt_ip_start);
			have_ipv4_dnsbl = 1;
		} else {
			tgt_ip_len = p - tgt_ip_start;
			++p;
			if (!strcasecmp(p, "name")) {
				type = DNSBL_TYPE_NAME;
				have_name_dnsbl = 1;
			} else if (!strcasecmp(p, "all-names")
				   || !strcasecmp(p, "all_names")) {
				type = DNSBL_TYPE_ALL_NAMES;
				have_name_dnsbl = 1;
			} else if (!strcasecmp(p, "IPV4")) {
				type = DNSBL_TYPE_IPV4;
				have_ipv4_dnsbl = 1;
			} else if (!strcasecmp(p, "IPV6")) {
				type = DNSBL_TYPE_IPV6;
				have_ipv6_dnsbl = 1;
			} else {
				dcc_pemsg(EX_NOHOST, emsg,
					  "unknown DNSBL type in \"%s\"",
					  entry);
				return 0;
			}
		}
	}
	/* assume 127.0.0.2 if the target address is missing */
	if (tgt_ip_len == 0) {
		BUFCPY(tgt_ip_buf, "127.0.0.2");
	} else {
		if (tgt_ip_len > ISZ(tgt_ip_buf)-1)
			tgt_ip_len = ISZ(tgt_ip_buf)-1;
		memcpy(tgt_ip_buf, tgt_ip_start, tgt_ip_len);
		tgt_ip_buf[tgt_ip_len] = '\0';
	}

	if (entry[0] == '.') {
		++entry;
		--dom_len;
	}
	if (dom_len >= ISZ(DNSBL_DOM) - INET6_ADDRSTRLEN*2) {
		/* we cannot fit the list and target names or address
		 * into a DNSBL_DOM field.  We need to do DNS lookups of
		 * names like 33.22.11.10.dnsbl.example.com or
		 * domain.dom.bl.example.com */
		dcc_pemsg(EX_NOHOST, emsg, "DNSBL name \"%s\" too long", entry);
		return 0;
	}
	memcpy(&parse_dp->dom.c, entry, dom_len);
	parse_dp->dom.c[dom_len] = '\0';

	if (!parse_dnsbl_addrs(emsg, entry, tgt_ip_buf))
		return 0;

	parse_dp->type = type;
	parse_tgts &= ~(DNSBL_HIT_MHOST_MX | DNSBL_HIT_URL_MX
			| DNSBL_HIT_MHOST_NS | DNSBL_HIT_URL_NS);
#ifdef MXNS_DNSBL
	if (parse_mx_ok) {
		if (parse_tgts & DNSBL_HIT_MHOST)
			parse_tgts |= DNSBL_HIT_MHOST_MX;
		if (parse_tgts & DNSBL_HIT_URL)
			parse_tgts |= DNSBL_HIT_URL_MX;
	}
	if (parse_ns_ok) {
		if (parse_tgts & DNSBL_HIT_MHOST)
			parse_tgts |= DNSBL_HIT_MHOST_NS;
		if (parse_tgts & DNSBL_HIT_URL)
			parse_tgts |= DNSBL_HIT_URL_NS;
	}
#endif
	parse_dp->tgt_hits = parse_tgts;
	parse_dp->gnum = parse_gnum;
	if (parse_tgts & DNSBL_HIT_WHITE)
		group_tgt_hits.w[parse_dp->gnum] |= parse_tgts;
	else
		group_tgt_hits.b[parse_dp->gnum] |= parse_tgts;

	parse_dp->reply = parse_reply;
	parse_dp->dom_len = dom_len+1;	/* count trailing '\0' */
	parse_dp->num = ++parse_dnum;

	/* link the lists as they were declared except that
	 * all whitelist must precede all blacklists */
	for (dpp = &dnsbls; ; dpp = &dp1->fwd) {
		dp1 = *dpp;
		if (!dp1
		    || ((parse_tgts & DNSBL_HIT_WHITE)
			&& !(dp1->tgt_hits & DNSBL_HIT_WHITE))) {
			parse_dp->fwd = dp1;
			*dpp = parse_dp;
			break;
		}
	}

	/* notice lists that duplicate previous lists
	 * and so can use previous look-up results */
	seen_dp = 0;
	for (dp1 = dnsbls; dp1; dp1 = dp1->fwd) {
		if (dp1 == parse_dp) {
			seen_dp = 1;
			continue;
		}
		if (parse_dp->type == dp1->type
		    && parse_dp->tgt_use_ipv46 == dp1->tgt_use_ipv46
		    && parse_dp->dom_len == dp1->dom_len
		    && parse_dp->dom_len != 0
		    && !memcmp(parse_dp->dom.c, dp1->dom.c,
			       parse_dp->dom_len)) {
			if (seen_dp) {
				dp1->tgt_hits |= DNSBL_HIT_DUP;
				parse_dp->dup_fwd = dp1;
			} else {
				parse_dp->tgt_hits |= DNSBL_HIT_DUP;
				parse_dp->dup_fwd = dp1->dup_fwd;
				dp1->dup_fwd = parse_dp;
			}
			break;
		}
	}
	parse_dp = 0;

	SAVE_ARG(entry);
	return 1;
#undef SAVE_ARG
}