Commit Diff


commit - 8b10295ec9ddde4f3bfef322b31d3601d6040c62
commit + 2880100ab9ccb2f797b41e2c8c615e947eb42f77
blob - 1210e46dd5c67d6073935d5542ac84dc5a6f6a15
blob + bc9167c11f07085a6c16b8b189afe0d91b2930f0
--- gotd/gotd.c
+++ gotd/gotd.c
@@ -866,6 +866,8 @@ gotd_shutdown(void)
 	}
 
 	kill_proc(gotd.listen_proc, 0);
+
+	free(gotd.default_sender);
 
 	log_info("terminating");
 	exit(0);
@@ -1293,7 +1295,202 @@ done:
 		/* This pipe is dead. Remove its event handler */
 		event_del(&iev->ev);
 		event_loopexit(NULL);
+	}
+}
+
+static const struct got_error *
+send_notification_target_email(struct gotd_imsgev *iev, const char *repo_name,
+    struct gotd_notification_target *target)
+{
+	struct gotd_imsg_notitfication_target_email itarget;
+	struct ibuf *wbuf = NULL;
+
+	memset(&itarget, 0, sizeof(itarget));
+
+	if (target->conf.email.sender)
+		itarget.sender_len = strlen(target->conf.email.sender);
+	else
+		itarget.sender_len = strlen(gotd.default_sender);
+	if (target->conf.email.recipient)
+		itarget.recipient_len = strlen(target->conf.email.recipient);
+	if (target->conf.email.responder)
+		itarget.responder_len = strlen(target->conf.email.responder);
+	if (target->conf.email.hostname)
+		itarget.hostname_len = strlen(target->conf.email.hostname);
+	if (target->conf.email.port)
+		itarget.port_len = strlen(target->conf.email.port);
+	itarget.repo_name_len = strlen(repo_name);
+
+	wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_EMAIL,
+	    0, 0, sizeof(itarget) + itarget.sender_len + itarget.recipient_len +
+	    itarget.responder_len + itarget.hostname_len + itarget.port_len +
+	    itarget.repo_name_len);
+	if (wbuf == NULL) {
+		return got_error_from_errno("imsg_create "
+		    "NOTIFICATION_TARGET_EMAIL");
+	}
+
+	if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) {
+		return got_error_from_errno("imsg_add "
+		    "NOTIFICATION_TARGET_EMAIL");
+	}
+	if (target->conf.email.sender) {
+		if (imsg_add(wbuf, target->conf.email.sender,
+		    itarget.sender_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_EMAIL");
+		}
+	} else {
+		if (imsg_add(wbuf, gotd.default_sender,
+		    itarget.sender_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_EMAIL");
+		}
+	}
+	if (target->conf.email.recipient) {
+		if (imsg_add(wbuf, target->conf.email.recipient,
+		    itarget.recipient_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_EMAIL");
+		}
+	}
+	if (target->conf.email.responder) {
+		if (imsg_add(wbuf, target->conf.email.responder,
+		    itarget.responder_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_EMAIL");
+		}
+	}
+	if (target->conf.email.hostname) {
+		if (imsg_add(wbuf, target->conf.email.hostname,
+		    itarget.hostname_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_EMAIL");
+		}
+	}
+	if (target->conf.email.port) {
+		if (imsg_add(wbuf, target->conf.email.port,
+		    itarget.port_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_EMAIL");
+		}
+	}
+	if (imsg_add(wbuf, repo_name, itarget.repo_name_len) == -1) {
+		return got_error_from_errno("imsg_add "
+		    "NOTIFICATION_TARGET_EMAIL");
+	}
+
+	imsg_close(&iev->ibuf, wbuf);
+	return gotd_imsg_flush(&iev->ibuf);
+}
+
+static const struct got_error *
+send_notification_target_http(struct gotd_imsgev *iev, const char *repo_name,
+    struct gotd_notification_target *target)
+{
+	struct gotd_imsg_notitfication_target_http itarget;
+	struct ibuf *wbuf = NULL;
+
+	memset(&itarget, 0, sizeof(itarget));
+
+	itarget.tls = target->conf.http.tls;
+	itarget.hostname_len = strlen(target->conf.http.hostname);
+	itarget.port_len = strlen(target->conf.http.port);
+	itarget.path_len = strlen(target->conf.http.path);
+	if (target->conf.http.auth)
+		itarget.auth_len = strlen(target->conf.http.auth);
+	if (target->conf.http.hmac)
+		itarget.hmac_len = strlen(target->conf.http.hmac);
+	itarget.repo_name_len = strlen(repo_name);
+
+	wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_HTTP,
+	    0, 0, sizeof(itarget) + itarget.hostname_len + itarget.port_len +
+	    itarget.path_len + itarget.auth_len + itarget.hmac_len +
+	    itarget.repo_name_len);
+	if (wbuf == NULL) {
+		return got_error_from_errno("imsg_create "
+		    "NOTIFICATION_TARGET_HTTP");
+	}
+
+	if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) {
+		return got_error_from_errno("imsg_add "
+		    "NOTIFICATION_TARGET_HTTP");
+	}
+	if (imsg_add(wbuf, target->conf.http.hostname,
+	    itarget.hostname_len) == -1) {
+		return got_error_from_errno("imsg_add "
+		    "NOTIFICATION_TARGET_HTTP");
+	}
+	if (imsg_add(wbuf, target->conf.http.port,
+	    itarget.port_len) == -1) {
+		return got_error_from_errno("imsg_add "
+		    "NOTIFICATION_TARGET_HTTP");
+	}
+	if (imsg_add(wbuf, target->conf.http.path,
+	    itarget.path_len) == -1) {
+		return got_error_from_errno("imsg_add "
+		    "NOTIFICATION_TARGET_HTTP");
+	}
+
+	if (target->conf.http.auth) {
+		if (imsg_add(wbuf, target->conf.http.auth,
+		    itarget.auth_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_HTTP");
+		}
+	}
+	if (target->conf.http.hmac) {
+		if (imsg_add(wbuf, target->conf.http.hmac,
+		    itarget.hmac_len) == -1) {
+			return got_error_from_errno("imsg_add "
+			    "NOTIFICATION_TARGET_HTTP");
+		}
+	}
+	if (imsg_add(wbuf, repo_name, itarget.repo_name_len) == -1) {
+		return got_error_from_errno("imsg_add "
+		    "NOTIFICATION_TARGET_HTTP");
+	}
+
+	imsg_close(&iev->ibuf, wbuf);
+	return gotd_imsg_flush(&iev->ibuf);
+}
+
+static const struct got_error *
+send_notification_target(struct gotd_imsgev *iev, const char *repo_name,
+    struct gotd_notification_target *target)
+{
+	const struct got_error *err = NULL;
+
+	switch (target->type) {
+	case GOTD_NOTIFICATION_VIA_EMAIL:
+		err = send_notification_target_email(iev, repo_name, target);
+		break;
+	case GOTD_NOTIFICATION_VIA_HTTP:
+		err = send_notification_target_http(iev, repo_name, target);
+		break;
+	default:
+		log_warn("unsupported notification target type %d",
+		    target->type);
+		break;
+	}
+
+	return err;
+}
+
+static const struct got_error *
+send_notification_targets(struct gotd_imsgev *iev, const char *repo_name,
+    struct gotd_notification_targets *targets)
+{
+	const struct got_error *err = NULL;
+	struct gotd_notification_target *target;
+
+	STAILQ_FOREACH(target, targets, entry) {
+		err = send_notification_target(iev, repo_name, target);
+		if (err)
+			return err;
 	}
+
+	return NULL;
 }
 
 static void
@@ -1333,6 +1530,17 @@ gotd_dispatch_notifier(int fd, short event, void *arg)
 			break;
 
 		switch (imsg.hdr.type) {
+		case GOTD_IMSG_NOTIFIER_READY: {
+			struct gotd_repo *repo;
+
+			TAILQ_FOREACH(repo, &gotd.repos, entry) {
+				err = send_notification_targets(iev,
+				    repo->name, &repo->notification_targets);
+				if (err)
+					break;
+			}
+			break;
+		}
 		default:
 			log_debug("unexpected imsg %d", imsg.hdr.type);
 			break;
@@ -1849,175 +2057,15 @@ send_request_timeout(struct gotd_imsgev *iev, struct t
 	}
 
 	return NULL;
-}
-
-static const struct got_error *
-send_notification_target_email(struct gotd_imsgev *iev,
-    struct gotd_notification_target *target)
-{
-	struct gotd_imsg_notitfication_target_email itarget;
-	struct ibuf *wbuf = NULL;
-
-	memset(&itarget, 0, sizeof(itarget));
-
-	if (target->conf.email.sender)
-		itarget.sender_len = strlen(target->conf.email.sender);
-	if (target->conf.email.recipient)
-		itarget.recipient_len = strlen(target->conf.email.recipient);
-	if (target->conf.email.responder)
-		itarget.responder_len = strlen(target->conf.email.responder);
-	if (target->conf.email.hostname)
-		itarget.hostname_len = strlen(target->conf.email.hostname);
-	if (target->conf.email.port)
-		itarget.port_len = strlen(target->conf.email.port);
-
-	wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_EMAIL,
-	    0, 0, sizeof(itarget) + itarget.sender_len + itarget.recipient_len +
-	    itarget.responder_len + itarget.hostname_len + itarget.port_len);
-	if (wbuf == NULL) {
-		return got_error_from_errno("imsg_create "
-		    "NOTIFICATION_TARGET_EMAIL");
-	}
-
-	if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) {
-		return got_error_from_errno("imsg_add "
-		    "NOTIFICATION_TARGET_EMAIL");
-	}
-	if (target->conf.email.sender) {
-		if (imsg_add(wbuf, target->conf.email.sender,
-		    itarget.sender_len) == -1) {
-			return got_error_from_errno("imsg_add "
-			    "NOTIFICATION_TARGET_EMAIL");
-		}
-	}
-	if (target->conf.email.recipient) {
-		if (imsg_add(wbuf, target->conf.email.recipient,
-		    itarget.recipient_len) == -1) {
-			return got_error_from_errno("imsg_add "
-			    "NOTIFICATION_TARGET_EMAIL");
-		}
-	}
-	if (target->conf.email.responder) {
-		if (imsg_add(wbuf, target->conf.email.responder,
-		    itarget.responder_len) == -1) {
-			return got_error_from_errno("imsg_add "
-			    "NOTIFICATION_TARGET_EMAIL");
-		}
-	}
-	if (target->conf.email.hostname) {
-		if (imsg_add(wbuf, target->conf.email.hostname,
-		    itarget.hostname_len) == -1) {
-			return got_error_from_errno("imsg_add "
-			    "NOTIFICATION_TARGET_EMAIL");
-		}
-	}
-	if (target->conf.email.port) {
-		if (imsg_add(wbuf, target->conf.email.port,
-		    itarget.port_len) == -1) {
-			return got_error_from_errno("imsg_add "
-			    "NOTIFICATION_TARGET_EMAIL");
-		}
-	}
-
-	imsg_close(&iev->ibuf, wbuf);
-	return gotd_imsg_flush(&iev->ibuf);
 }
 
 static const struct got_error *
-send_notification_target_http(struct gotd_imsgev *iev,
-    struct gotd_notification_target *target)
-{
-	struct gotd_imsg_notitfication_target_http itarget;
-	struct ibuf *wbuf = NULL;
-
-	memset(&itarget, 0, sizeof(itarget));
-
-	itarget.tls = target->conf.http.tls;
-	itarget.hostname_len = strlen(target->conf.http.hostname);
-	itarget.port_len = strlen(target->conf.http.port);
-	itarget.path_len = strlen(target->conf.http.path);
-	if (target->conf.http.auth)
-		itarget.auth_len = strlen(target->conf.http.auth);
-	if (target->conf.http.hmac)
-		itarget.hmac_len = strlen(target->conf.http.hmac);
-
-	wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_HTTP,
-	    0, 0, sizeof(itarget) + itarget.hostname_len + itarget.port_len +
-	    itarget.path_len + itarget.auth_len + itarget.hmac_len);
-	if (wbuf == NULL) {
-		return got_error_from_errno("imsg_create "
-		    "NOTIFICATION_TARGET_HTTP");
-	}
-
-	if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) {
-		return got_error_from_errno("imsg_add "
-		    "NOTIFICATION_TARGET_HTTP");
-	}
-	if (imsg_add(wbuf, target->conf.http.hostname,
-	    itarget.hostname_len) == -1) {
-		return got_error_from_errno("imsg_add "
-		    "NOTIFICATION_TARGET_HTTP");
-	}
-	if (imsg_add(wbuf, target->conf.http.port,
-	    itarget.port_len) == -1) {
-		return got_error_from_errno("imsg_add "
-		    "NOTIFICATION_TARGET_HTTP");
-	}
-	if (imsg_add(wbuf, target->conf.http.path,
-	    itarget.path_len) == -1) {
-		return got_error_from_errno("imsg_add "
-		    "NOTIFICATION_TARGET_HTTP");
-	}
-
-	if (target->conf.http.auth) {
-		if (imsg_add(wbuf, target->conf.http.auth,
-		    itarget.auth_len) == -1) {
-			return got_error_from_errno("imsg_add "
-			    "NOTIFICATION_TARGET_HTTP");
-		}
-	}
-	if (target->conf.http.hmac) {
-		if (imsg_add(wbuf, target->conf.http.hmac,
-		    itarget.hmac_len) == -1) {
-			return got_error_from_errno("imsg_add "
-			    "NOTIFICATION_TARGET_HTTP");
-		}
-	}
-
-	imsg_close(&iev->ibuf, wbuf);
-	return gotd_imsg_flush(&iev->ibuf);
-}
-
-static const struct got_error *
-send_notification_target(struct gotd_imsgev *iev,
-    struct gotd_notification_target *target)
-{
-	const struct got_error *err = NULL;
-
-	switch (target->type) {
-	case GOTD_NOTIFICATION_VIA_EMAIL:
-		err = send_notification_target_email(iev, target);
-		break;
-	case GOTD_NOTIFICATION_VIA_HTTP:
-		err = send_notification_target_http(iev, target);
-		break;
-	default:
-		log_warn("unsupported notification target type %d",
-		    target->type);
-		break;
-	}
-
-	return err;
-}
-
-static const struct got_error *
 send_notification_config(struct gotd_imsgev *iev, char *repo_name)
 {
 	const struct got_error *err = NULL;
 	struct gotd_repo *repo;
 	struct got_pathlist_entry *pe;
 	struct gotd_imsg_pathlist ilist;
-	struct gotd_notification_target *target;
 
 	memset(&ilist, 0, sizeof(ilist));
 
@@ -2059,13 +2107,8 @@ send_notification_config(struct gotd_imsgev *iev, char
 		}
 	}
 
-	STAILQ_FOREACH(target, &repo->notification_targets, entry) {
-		err = send_notification_target(iev, target);
-		if (err)
-			return err;
-	}
-
-	return NULL;
+	return send_notification_targets(iev, repo->name,
+	    &repo->notification_targets);
 }
 
 static void
@@ -2617,6 +2660,7 @@ start_notifier(char *argv0, const char *confpath, int 
 	proc->iev.handler_arg = NULL;
 	event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
 	    gotd_dispatch_notifier, &proc->iev);
+	gotd_imsg_event_add(&proc->iev);
 
 	gotd.notify_proc = proc;
 }
@@ -2895,7 +2939,6 @@ main(int argc, char **argv)
 	struct event evsigint, evsigterm, evsighup, evsigusr1, evsigchld;
 	int *pack_fds = NULL, *temp_fds = NULL;
 	struct gotd_repo *repo = NULL;
-	char *default_sender = NULL;
 	char hostname[_POSIX_HOST_NAME_MAX + 1];
 	FILE *fp;
 	FILE *diff_f1 = NULL, *diff_f2 = NULL, *tmp_f1 = NULL, *tmp_f2 = NULL;
@@ -2993,7 +3036,7 @@ main(int argc, char **argv)
 
 	if (proc_id != GOTD_PROC_LISTEN && proc_id != GOTD_PROC_AUTH &&
 	    proc_id != GOTD_PROC_REPO_WRITE &&
-	    proc_id != GOTD_PROC_SESSION_WRITE) {
+	    proc_id != GOTD_PROC_SESSION_WRITE && proc_id != GOTD_PROC_NOTIFY) {
 		if (gotd_parse_config(confpath, proc_id, secrets, &gotd) != 0)
 			return 1;
 
@@ -3050,7 +3093,7 @@ main(int argc, char **argv)
 
 		if (gethostname(hostname, sizeof(hostname)) == -1)
 			fatal("gethostname");
-		if (asprintf(&default_sender, "%s@%s", pw->pw_name,
+		if (asprintf(&gotd.default_sender, "%s@%s", pw->pw_name,
 		    hostname) == -1)
 			fatal("asprintf");
 	}
@@ -3252,9 +3295,7 @@ main(int argc, char **argv)
 		 */
 		unveil_notification_helpers();
 
-		drop_privs(pw);
-
-		notify_main(title, &gotd.repos, default_sender);
+		notify_main(title);
 		/* NOTREACHED */
 		exit(0);
 	default:
@@ -3340,7 +3381,6 @@ main(int argc, char **argv)
 
 	free(repo_path);
 	free(secretspath);
-	free(default_sender);
 	gotd_shutdown();
 
 	return 0;
blob - 95ebcef04adc3f9d2afc5df131874ee0f9170ed7
blob + f04ba7601ab2f6ff8ec1e20c104c69749cacf93a
--- gotd/gotd.h
+++ gotd/gotd.h
@@ -181,6 +181,7 @@ struct gotd {
 	struct gotd_uid_connection_limit *connection_limits;
 	size_t nconnection_limits;
 	struct gotd_secrets *secrets;
+	char *default_sender;
 
 	char *argv0;
 	const char *confpath;
@@ -273,6 +274,7 @@ enum gotd_imsg_type {
 	GOTD_IMSG_PROTECTED_BRANCHES_ELEM,
 
 	/* Notify child process. */
+	GOTD_IMSG_NOTIFIER_READY,
 	GOTD_IMSG_NOTIFICATION_REFS,
 	GOTD_IMSG_NOTIFICATION_REFS_ELEM,
 	GOTD_IMSG_NOTIFICATION_REF_NAMESPACES,
@@ -591,10 +593,11 @@ struct gotd_imsg_notitfication_target_email {
 	size_t responder_len;
 	size_t hostname_len;
 	size_t port_len;
+	size_t repo_name_len;
 
 	/*
 	 * Followed by sender_len + responder_len + responder_len +
-	 * hostname_len + port_len bytes.
+	 * hostname_len + port_len + repo_name_len bytes.
 	 */
 };
 
@@ -606,10 +609,11 @@ struct gotd_imsg_notitfication_target_http {
 	size_t path_len;
 	size_t auth_len;
 	size_t hmac_len;;
+	size_t repo_name_len;
 
 	/*
 	 * Followed by hostname_len + port_len + path_len + auth_len +
-	 * hmac_len bytes.
+	 * hmac_len + repo_name_len bytes.
 	 */
 };
 
@@ -645,6 +649,7 @@ struct gotd_uid_connection_limit *gotd_find_uid_connec
 int gotd_parseuid(const char *s, uid_t *uid);
 const struct got_error *gotd_parse_url(char **, char **, char **,
     char **, const char *);
+const struct got_error *gotd_conf_new_repo(struct gotd_repo **, const char *);
 
 /* imsg.c */
 const struct got_error *gotd_imsg_flush(struct imsgbuf *);
@@ -668,3 +673,8 @@ void gotd_imsg_send_nak(struct got_object_id *, struct
 const struct got_error *gotd_imsg_recv_pathlist(size_t *, struct imsg *);
 const struct got_error *gotd_imsg_recv_pathlist_elem(struct imsg *,
     struct got_pathlist_head *);
+void gotd_free_notification_target(struct gotd_notification_target *);
+const struct got_error *gotd_imsg_recv_notification_target_email(char **,
+    struct gotd_notification_target **, struct imsg *);
+const struct got_error *gotd_imsg_recv_notification_target_http(char **,
+    struct gotd_notification_target **, struct imsg *);
blob - e0c130803906829b51d5f392e75336ea4f953991
blob + ee2ae7e5319116d7f867753f8682273729ff9f20
--- gotd/imsg.c
+++ gotd/imsg.c
@@ -250,5 +250,284 @@ gotd_imsg_recv_pathlist_elem(struct imsg *imsg, struct
 	if (err || pe == NULL)
 		free(path);
 	return err;
+}
+
+void
+gotd_free_notification_target(struct gotd_notification_target *target)
+{
+	if (target == NULL)
+		return;
+
+	switch (target->type) {
+	case GOTD_NOTIFICATION_VIA_EMAIL:
+		free(target->conf.email.sender);
+		free(target->conf.email.recipient);
+		free(target->conf.email.responder);
+		free(target->conf.email.hostname);
+		free(target->conf.email.port);
+		break;
+	case GOTD_NOTIFICATION_VIA_HTTP:
+		free(target->conf.http.hostname);
+		free(target->conf.http.port);
+		free(target->conf.http.path);
+		free(target->conf.http.auth);
+		free(target->conf.http.hmac);
+		break;
+	default:
+		break;
+	}
+
+	free(target);
 }
 
+const struct got_error *
+gotd_imsg_recv_notification_target_email(char **repo_name,
+    struct gotd_notification_target **new_target, struct imsg *imsg)
+{
+	const struct got_error *err = NULL;
+	struct gotd_imsg_notitfication_target_email itarget;
+	struct gotd_notification_target *target;
+	size_t datalen;
+
+	if (repo_name)
+		*repo_name = NULL;
+	*new_target = NULL;
+
+	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+	if (datalen < sizeof(itarget))
+		return got_error(GOT_ERR_PRIVSEP_LEN);
+	memcpy(&itarget, imsg->data, sizeof(itarget));
+
+	if (datalen != sizeof(itarget) + itarget.sender_len +
+	    itarget.recipient_len + itarget.responder_len +
+	    itarget.hostname_len + itarget.port_len + itarget.repo_name_len)
+		return got_error(GOT_ERR_PRIVSEP_LEN);
+	if (itarget.sender_len == 0 || itarget.recipient_len == 0 ||
+	    itarget.repo_name_len == 0)
+		return got_error(GOT_ERR_PRIVSEP_LEN);
+
+	target = calloc(1, sizeof(*target));
+	if (target == NULL)
+		return got_error_from_errno("calloc");
+
+	target->type = GOTD_NOTIFICATION_VIA_EMAIL;
+
+	if (itarget.sender_len) {
+		target->conf.email.sender = strndup(imsg->data +
+		    sizeof(itarget), itarget.sender_len);
+		if (target->conf.email.sender == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(target->conf.email.sender) != itarget.sender_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			goto done;
+		}
+	}
+
+	target->conf.email.recipient = strndup(imsg->data + sizeof(itarget) +
+	    itarget.sender_len, itarget.recipient_len);
+	if (target->conf.email.recipient == NULL) {
+		err = got_error_from_errno("strndup");
+		goto done;
+	}
+	if (strlen(target->conf.email.recipient) != itarget.recipient_len) {
+		err = got_error(GOT_ERR_PRIVSEP_LEN);
+		goto done;
+	}
+	
+	if (itarget.responder_len) {
+		target->conf.email.responder = strndup(imsg->data +
+		    sizeof(itarget) + itarget.sender_len + itarget.recipient_len,
+		    itarget.responder_len);
+		if (target->conf.email.responder == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(target->conf.email.responder) !=
+		    itarget.responder_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			goto done;
+		}
+	}
+
+	if (itarget.hostname_len) {
+		target->conf.email.hostname = strndup(imsg->data +
+		    sizeof(itarget) + itarget.sender_len +
+		    itarget.recipient_len + itarget.responder_len,
+		    itarget.hostname_len);
+		if (target->conf.email.hostname == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(target->conf.email.hostname) !=
+		    itarget.hostname_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			goto done;
+		}
+	}
+
+	if (itarget.port_len) {
+		target->conf.email.port = strndup(imsg->data +
+		    sizeof(itarget) + itarget.sender_len +
+		    itarget.recipient_len + itarget.responder_len +
+		    itarget.hostname_len, itarget.port_len);
+		if (target->conf.email.port == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(target->conf.email.port) != itarget.port_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			goto done;
+		}
+	}
+
+	if (repo_name) {
+		*repo_name = strndup(imsg->data +
+		    sizeof(itarget) + itarget.sender_len +
+		    itarget.recipient_len + itarget.responder_len +
+		    itarget.hostname_len + itarget.port_len,
+		    itarget.repo_name_len);
+		if (*repo_name == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(*repo_name) != itarget.repo_name_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			free(*repo_name);
+			*repo_name = NULL;
+			goto done;
+		}
+	}
+
+	*new_target = target;
+done:
+	if (err)
+		gotd_free_notification_target(target);
+	return err;
+}
+
+const struct got_error *
+gotd_imsg_recv_notification_target_http(char **repo_name,
+    struct gotd_notification_target **new_target, struct imsg *imsg)
+{
+	const struct got_error *err = NULL;
+	struct gotd_imsg_notitfication_target_http itarget;
+	struct gotd_notification_target *target;
+	size_t datalen;
+
+	if (repo_name)
+		*repo_name = NULL;
+
+	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+	if (datalen < sizeof(itarget))
+		return got_error(GOT_ERR_PRIVSEP_LEN);
+	memcpy(&itarget, imsg->data, sizeof(itarget));
+
+	if (datalen != sizeof(itarget) + itarget.hostname_len +
+	    itarget.port_len + itarget.path_len + itarget.auth_len +
+	    itarget.hmac_len + itarget.repo_name_len)
+		return got_error(GOT_ERR_PRIVSEP_LEN);
+
+	if (itarget.hostname_len == 0 || itarget.port_len == 0 ||
+	    itarget.path_len == 0 || itarget.repo_name_len == 0)
+		return got_error(GOT_ERR_PRIVSEP_LEN);
+
+	target = calloc(1, sizeof(*target));
+	if (target == NULL)
+		return got_error_from_errno("calloc");
+
+	target->type = GOTD_NOTIFICATION_VIA_HTTP;
+
+	target->conf.http.tls = itarget.tls;
+
+	target->conf.http.hostname = strndup(imsg->data +
+	    sizeof(itarget), itarget.hostname_len);
+	if (target->conf.http.hostname == NULL) {
+		err = got_error_from_errno("strndup");
+		goto done;
+	}
+	if (strlen(target->conf.http.hostname) != itarget.hostname_len) {
+		err = got_error(GOT_ERR_PRIVSEP_LEN);
+		goto done;
+	}
+
+	target->conf.http.port = strndup(imsg->data + sizeof(itarget) +
+	    itarget.hostname_len, itarget.port_len);
+	if (target->conf.http.port == NULL) {
+		err = got_error_from_errno("strndup");
+		goto done;
+	}
+	if (strlen(target->conf.http.port) != itarget.port_len) {
+		err = got_error(GOT_ERR_PRIVSEP_LEN);
+		goto done;
+	}
+	
+	target->conf.http.path = strndup(imsg->data +
+	    sizeof(itarget) + itarget.hostname_len + itarget.port_len,
+	    itarget.path_len);
+	if (target->conf.http.path == NULL) {
+		err = got_error_from_errno("strndup");
+		goto done;
+	}
+	if (strlen(target->conf.http.path) != itarget.path_len) {
+		err = got_error(GOT_ERR_PRIVSEP_LEN);
+		goto done;
+	}
+
+	if (itarget.auth_len) {
+		target->conf.http.auth = strndup(imsg->data +
+		    sizeof(itarget) + itarget.hostname_len +
+		    itarget.port_len + itarget.path_len,
+		    itarget.auth_len);
+		if (target->conf.http.auth == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(target->conf.http.auth) != itarget.auth_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			goto done;
+		}
+	}
+
+	if (itarget.hmac_len) {
+		target->conf.http.hmac = strndup(imsg->data +
+		    sizeof(itarget) + itarget.hostname_len +
+		    itarget.port_len + itarget.path_len +
+		    itarget.auth_len, itarget.hmac_len);
+		if (target->conf.http.hmac == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(target->conf.http.hmac) != itarget.hmac_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			goto done;
+		}
+	}
+
+	if (repo_name) {
+		*repo_name = strndup(imsg->data +
+		    sizeof(itarget) + itarget.hostname_len +
+		    itarget.port_len + itarget.path_len +
+		    itarget.auth_len + itarget.hmac_len,
+		    itarget.repo_name_len);
+		if (*repo_name == NULL) {
+			err = got_error_from_errno("strndup");
+			goto done;
+		}
+		if (strlen(*repo_name) != itarget.repo_name_len) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			free(*repo_name);
+			*repo_name = NULL;
+			goto done;
+		}
+	}
+		
+	*new_target = target;
+done:
+	if (err)
+		gotd_free_notification_target(target);
+	return err;
+}
+
+
blob - 78a75d6ba9a3cacdcae284eeba502b2011158558
blob + 2713d529309f6d5bc43ac78227353480490cb126
--- gotd/notify.c
+++ gotd/notify.c
@@ -50,8 +50,7 @@ static struct gotd_notify {
 	pid_t pid;
 	const char *title;
 	struct gotd_imsgev parent_iev;
-	struct gotd_repolist *repos;
-	const char *default_sender;
+	struct gotd_repolist repos;
 } gotd_notify;
 
 struct gotd_notify_session {
@@ -239,10 +238,7 @@ notify_email(struct gotd_notification_target *target, 
 	argv[i++] = GOTD_PATH_PROG_NOTIFY_EMAIL;
 
 	argv[i++] = "-f";
-	if (target->conf.email.sender)
-		argv[i++] = target->conf.email.sender;
-	else
-		argv[i++] = gotd_notify.default_sender;
+	argv[i++] = target->conf.email.sender;
 
 	if (target->conf.email.responder) {
 		argv[i++] = "-r";
@@ -331,7 +327,7 @@ send_notification(struct imsg *imsg, struct gotd_imsge
 	if (datalen != sizeof(inotify) + inotify.username_len)
 		return got_error(GOT_ERR_PRIVSEP_LEN);
 
-	repo = gotd_find_repo_by_name(inotify.repo_name, gotd_notify.repos);
+	repo = gotd_find_repo_by_name(inotify.repo_name, &gotd_notify.repos);
 	if (repo == NULL)
 		return got_error(GOT_ERR_PRIVSEP_MSG);
 
@@ -501,6 +497,24 @@ notify_ibuf_get_str(char **ret, struct ibuf *ibuf)
 	return NULL;
 }
 
+static const struct got_error *
+add_notification_target(const char *repo_name,
+    struct gotd_notification_target *target)
+{
+	const struct got_error *err = NULL;
+	struct gotd_repo *repo;
+
+	repo = gotd_find_repo_by_name(repo_name, &gotd_notify.repos);
+	if (repo == NULL) {
+		err = gotd_conf_new_repo(&repo, repo_name);
+		if (err)
+			return err;
+		TAILQ_INSERT_TAIL(&gotd_notify.repos, repo, entry);
+	}
+
+	STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry);
+	return NULL;
+}
 static void
 notify_dispatch(int fd, short event, void *arg)
 {
@@ -538,6 +552,32 @@ notify_dispatch(int fd, short event, void *arg)
 			break;
 
 		switch (imsg.hdr.type) {
+		case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL: {
+			struct gotd_notification_target *target;
+			char *repo_name;
+
+			err = gotd_imsg_recv_notification_target_email(
+			    &repo_name, &target, &imsg);
+			if (err)
+				break;
+			err = add_notification_target(repo_name, target);
+			if (err)
+				gotd_free_notification_target(target);
+			break;
+		}
+		case GOTD_IMSG_NOTIFICATION_TARGET_HTTP: {
+			struct gotd_notification_target *target;
+			char *repo_name;
+
+			err = gotd_imsg_recv_notification_target_http(
+			    &repo_name, &target, &imsg);
+			if (err)
+				break;
+			err = add_notification_target(repo_name, target);
+			if (err)
+				gotd_free_notification_target(target);
+			break;
+		}
 		case GOTD_IMSG_CONNECT_SESSION:
 			err = recv_session(&imsg);
 			break;
@@ -602,8 +642,7 @@ done:
 }
 
 void
-notify_main(const char *title, struct gotd_repolist *repos,
-    const char *default_sender)
+notify_main(const char *title)
 {
 	const struct got_error *err = NULL;
 	struct event evsigint, evsigterm, evsighup, evsigusr1;
@@ -611,9 +650,8 @@ notify_main(const char *title, struct gotd_repolist *r
 	arc4random_buf(&sessions_hash_key, sizeof(sessions_hash_key));
 
 	gotd_notify.title = title;
-	gotd_notify.repos = repos;
-	gotd_notify.default_sender = default_sender;
 	gotd_notify.pid = getpid();
+	TAILQ_INIT(&gotd_notify.repos);
 
 	signal_set(&evsigint, SIGINT, gotd_notify_sighdlr, NULL);
 	signal_set(&evsigterm, SIGTERM, gotd_notify_sighdlr, NULL);
@@ -635,7 +673,9 @@ notify_main(const char *title, struct gotd_repolist *r
 	gotd_notify.parent_iev.handler_arg = NULL;
 	event_set(&gotd_notify.parent_iev.ev, gotd_notify.parent_iev.ibuf.fd,
 	    EV_READ, notify_dispatch, &gotd_notify.parent_iev);
-	gotd_imsg_event_add(&gotd_notify.parent_iev);
+	if (gotd_imsg_compose_event(&gotd_notify.parent_iev,
+	    GOTD_IMSG_NOTIFIER_READY, GOTD_PROC_NOTIFY, -1, NULL, 0) == -1)
+		fatal("imsg compose NOTIFIER_READY");
 
 	event_dispatch();
 
blob - 8173549e2a96f7a2443ff8bd53806411e4312d57
blob + 8f9d9538652602ced40b216c70debce37cbda0db
--- gotd/notify.h
+++ gotd/notify.h
@@ -14,4 +14,4 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-void notify_main(const char *, struct gotd_repolist *, const char *);
+void notify_main(const char *);
blob - daaf2c2aa310ab499970f60fa62149dff6b06347
blob + df4c6ae0933e6455023be61dfd1d6524ea69cbb3
--- gotd/parse.y
+++ gotd/parse.y
@@ -327,8 +327,7 @@ notifyflags_l	: notifyflags optnl notifyflags_l
 		;
 
 notifyflags	: BRANCH STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_branch(new_repo, $2)) {
 					free($2);
 					YYERROR;
@@ -337,8 +336,7 @@ notifyflags	: BRANCH STRING {
 			free($2);
 		}
 		| REFERENCE NAMESPACE STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_ref_namespace(new_repo, $3)) {
 					free($3);
 					YYERROR;
@@ -347,8 +345,7 @@ notifyflags	: BRANCH STRING {
 			free($3);
 		}
 		| EMAIL TO STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    NULL, NULL, NULL)) {
 					free($3);
@@ -358,8 +355,7 @@ notifyflags	: BRANCH STRING {
 			free($3);
 		}
 		| EMAIL FROM STRING TO STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    NULL, NULL, NULL)) {
 					free($3);
@@ -371,8 +367,7 @@ notifyflags	: BRANCH STRING {
 			free($5);
 		}
 		| EMAIL TO STRING REPLY TO STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    $6, NULL, NULL)) {
 					free($3);
@@ -384,8 +379,7 @@ notifyflags	: BRANCH STRING {
 			free($6);
 		}
 		| EMAIL FROM STRING TO STRING REPLY TO STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    $8, NULL, NULL)) {
 					free($3);
@@ -399,8 +393,7 @@ notifyflags	: BRANCH STRING {
 			free($8);
 		}
 		| EMAIL TO STRING RELAY STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    NULL, $5, NULL)) {
 					free($3);
@@ -412,8 +405,7 @@ notifyflags	: BRANCH STRING {
 			free($5);
 		}
 		| EMAIL FROM STRING TO STRING RELAY STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    NULL, $7, NULL)) {
 					free($3);
@@ -427,8 +419,7 @@ notifyflags	: BRANCH STRING {
 			free($7);
 		}
 		| EMAIL TO STRING REPLY TO STRING RELAY STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    $6, $8, NULL)) {
 					free($3);
@@ -442,8 +433,7 @@ notifyflags	: BRANCH STRING {
 			free($8);
 		}
 		| EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    $8, $10, NULL)) {
 					free($3);
@@ -459,8 +449,7 @@ notifyflags	: BRANCH STRING {
 			free($10);
 		}
 		| EMAIL TO STRING RELAY STRING PORT STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    NULL, $5, $7)) {
 					free($3);
@@ -474,8 +463,7 @@ notifyflags	: BRANCH STRING {
 			free($7);
 		}
 		| EMAIL FROM STRING TO STRING RELAY STRING PORT STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    NULL, $7, $9)) {
 					free($3);
@@ -491,8 +479,7 @@ notifyflags	: BRANCH STRING {
 			free($9);
 		}
 		| EMAIL TO STRING REPLY TO STRING RELAY STRING PORT STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    $6, $8, $10)) {
 					free($3);
@@ -508,8 +495,7 @@ notifyflags	: BRANCH STRING {
 			free($10);
 		}
 		| EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    $8, $10, $12)) {
 					free($3);
@@ -527,8 +513,7 @@ notifyflags	: BRANCH STRING {
 			free($12);
 		}
 		| EMAIL TO STRING RELAY STRING PORT NUMBER {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    NULL, $5, port_sprintf($7))) {
 					free($3);
@@ -540,8 +525,7 @@ notifyflags	: BRANCH STRING {
 			free($5);
 		}
 		| EMAIL FROM STRING TO STRING RELAY STRING PORT NUMBER {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    NULL, $7, port_sprintf($9))) {
 					free($3);
@@ -555,8 +539,7 @@ notifyflags	: BRANCH STRING {
 			free($7);
 		}
 		| EMAIL TO STRING REPLY TO STRING RELAY STRING PORT NUMBER {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, NULL, $3,
 				    $6, $8, port_sprintf($10))) {
 					free($3);
@@ -570,8 +553,7 @@ notifyflags	: BRANCH STRING {
 			free($8);
 		}
 		| EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT NUMBER {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_email(new_repo, $3, $5,
 				    $8, $10, port_sprintf($12))) {
 					free($3);
@@ -587,8 +569,7 @@ notifyflags	: BRANCH STRING {
 			free($10);
 		}
 		| URL STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_http(new_repo, $2, NULL,
 				    NULL, 0)) {
 					free($2);
@@ -598,8 +579,7 @@ notifyflags	: BRANCH STRING {
 			free($2);
 		}
 		| URL STRING AUTH STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_http(new_repo, $2, $4, NULL,
 				    0)) {
 					free($2);
@@ -611,8 +591,7 @@ notifyflags	: BRANCH STRING {
 			free($4);
 		}
 		| URL STRING AUTH STRING INSECURE {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_http(new_repo, $2, $4, NULL,
 				    1)) {
 					free($2);
@@ -624,8 +603,7 @@ notifyflags	: BRANCH STRING {
 			free($4);
 		}
 		| URL STRING HMAC STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_http(new_repo, $2, NULL, $4,
 				    0)) {
 					free($2);
@@ -637,8 +615,7 @@ notifyflags	: BRANCH STRING {
 			free($4);
 		}
 		| URL STRING AUTH STRING HMAC STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_http(new_repo, $2, $4, $6,
 				    0)) {
 					free($2);
@@ -652,8 +629,7 @@ notifyflags	: BRANCH STRING {
 			free($6);
 		}
 		| URL STRING AUTH STRING INSECURE HMAC STRING {
-			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			if (gotd_proc_id == GOTD_PROC_GOTD) {
 				if (conf_notify_http(new_repo, $2, $4, $7,
 				    1)) {
 					free($2);
@@ -680,8 +656,7 @@ repository	: REPOSITORY STRING {
 			}
 
 			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_GITWRAPPER |
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			    gotd_proc_id == GOTD_PROC_GITWRAPPER) {
 				new_repo = conf_new_repo($2);
 			}
 			free($2);
@@ -691,8 +666,7 @@ repository	: REPOSITORY STRING {
 
 repoopts1	: PATH STRING {
 			if (gotd_proc_id == GOTD_PROC_GOTD ||
-			    gotd_proc_id == GOTD_PROC_GITWRAPPER ||
-			    gotd_proc_id == GOTD_PROC_NOTIFY) {
+			    gotd_proc_id == GOTD_PROC_GITWRAPPER) {
 				if (!got_path_is_absolute($2)) {
 					yyerror("%s: path %s is not absolute",
 					    __func__, $2);
@@ -1279,22 +1253,14 @@ conf_limit_user_connections(const char *user, int maxi
 	return 0;
 }
 
-static struct gotd_repo *
-conf_new_repo(const char *name)
+const struct got_error *
+gotd_conf_new_repo(struct gotd_repo **new_repo, const char *name)
 {
 	struct gotd_repo *repo;
-
-	if (name[0] == '\0') {
-		fatalx("syntax error: empty repository name found in %s",
-		    file->name);
-	}
 
-	if (strchr(name, '\n') != NULL)
-		fatalx("repository names must not contain linefeeds: %s", name);
-
 	repo = calloc(1, sizeof(*repo));
 	if (repo == NULL)
-		fatalx("%s: calloc", __func__);
+		return got_error_from_errno("calloc");
 
 	STAILQ_INIT(&repo->rules);
 	RB_INIT(&repo->protected_tag_namespaces);
@@ -1306,9 +1272,34 @@ conf_new_repo(const char *name)
 	STAILQ_INIT(&repo->notification_targets);
 
 	if (strlcpy(repo->name, name, sizeof(repo->name)) >=
-	    sizeof(repo->name))
-		fatalx("%s: strlcpy", __func__);
+	    sizeof(repo->name)) {
+		free(repo);
+		return got_error_msg(GOT_ERR_NO_SPACE,
+		    "repository name too long");
+	}
 
+	*new_repo = repo;
+	return NULL;
+}
+
+static struct gotd_repo *
+conf_new_repo(const char *name)
+{
+	const struct got_error *err;
+	struct gotd_repo *repo;
+
+	if (name[0] == '\0') {
+		fatalx("syntax error: empty repository name found in %s",
+		    file->name);
+	}
+
+	if (strchr(name, '\n') != NULL)
+		fatalx("repository names must not contain linefeeds: %s", name);
+
+	err = gotd_conf_new_repo(&repo, name);
+	if (err)
+		fatalx("%s", err->msg);
+
 	TAILQ_INSERT_TAIL(&gotd->repos, repo, entry);
 	gotd->nrepos++;
 
blob - d139091dacf9e073b2a167c8dca8537a36c7c461
blob + 8ab93f57b38a1436a2f09373f54f92d6d3f6aa96
--- gotd/session_write.c
+++ gotd/session_write.c
@@ -1762,240 +1762,6 @@ recv_repo_child(struct imsg *imsg)
 		fatal("pledge");
 
 	return NULL;
-}
-
-static void
-free_notification_target(struct gotd_notification_target *target)
-{
-	if (target == NULL)
-		return;
-
-	switch (target->type) {
-	case GOTD_NOTIFICATION_VIA_EMAIL:
-		free(target->conf.email.sender);
-		free(target->conf.email.recipient);
-		free(target->conf.email.responder);
-		free(target->conf.email.hostname);
-		free(target->conf.email.port);
-		break;
-	case GOTD_NOTIFICATION_VIA_HTTP:
-		free(target->conf.http.hostname);
-		free(target->conf.http.port);
-		free(target->conf.http.path);
-		free(target->conf.http.auth);
-		free(target->conf.http.hmac);
-		break;
-	default:
-		break;
-	}
-
-	free(target);
-}
-
-static const struct got_error *
-recv_notification_target_email(struct imsg *imsg)
-{
-	const struct got_error *err = NULL;
-	struct gotd_imsg_notitfication_target_email itarget;
-	struct gotd_notification_target *target;
-	size_t datalen;
-
-	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
-	if (datalen < sizeof(itarget))
-		return got_error(GOT_ERR_PRIVSEP_LEN);
-	memcpy(&itarget, imsg->data, sizeof(itarget));
-
-	if (datalen != sizeof(itarget) + itarget.sender_len +
-	    itarget.recipient_len + itarget.responder_len +
-	    itarget.hostname_len + itarget.port_len)
-		return got_error(GOT_ERR_PRIVSEP_LEN);
-	if (itarget.recipient_len == 0)
-		return got_error(GOT_ERR_PRIVSEP_LEN);
-
-	target = calloc(1, sizeof(*target));
-	if (target == NULL)
-		return got_error_from_errno("calloc");
-
-	target->type = GOTD_NOTIFICATION_VIA_EMAIL;
-
-	if (itarget.sender_len) {
-		target->conf.email.sender = strndup(imsg->data +
-		    sizeof(itarget), itarget.sender_len);
-		if (target->conf.email.sender == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		if (strlen(target->conf.email.sender) != itarget.sender_len) {
-			err = got_error(GOT_ERR_PRIVSEP_LEN);
-			goto done;
-		}
-	}
-
-	target->conf.email.recipient = strndup(imsg->data + sizeof(itarget) +
-	    itarget.sender_len, itarget.recipient_len);
-	if (target->conf.email.recipient == NULL) {
-		err = got_error_from_errno("strndup");
-		goto done;
-	}
-	if (strlen(target->conf.email.recipient) != itarget.recipient_len) {
-		err = got_error(GOT_ERR_PRIVSEP_LEN);
-		goto done;
-	}
-	
-	if (itarget.responder_len) {
-		target->conf.email.responder = strndup(imsg->data +
-		    sizeof(itarget) + itarget.sender_len + itarget.recipient_len,
-		    itarget.responder_len);
-		if (target->conf.email.responder == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		if (strlen(target->conf.email.responder) !=
-		    itarget.responder_len) {
-			err = got_error(GOT_ERR_PRIVSEP_LEN);
-			goto done;
-		}
-	}
-
-	if (itarget.hostname_len) {
-		target->conf.email.hostname = strndup(imsg->data +
-		    sizeof(itarget) + itarget.sender_len +
-		    itarget.recipient_len + itarget.responder_len,
-		    itarget.hostname_len);
-		if (target->conf.email.hostname == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		if (strlen(target->conf.email.hostname) !=
-		    itarget.hostname_len) {
-			err = got_error(GOT_ERR_PRIVSEP_LEN);
-			goto done;
-		}
-	}
-
-	if (itarget.port_len) {
-		target->conf.email.port = strndup(imsg->data +
-		    sizeof(itarget) + itarget.sender_len +
-		    itarget.recipient_len + itarget.responder_len +
-		    itarget.hostname_len, itarget.port_len);
-		if (target->conf.email.port == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		if (strlen(target->conf.email.port) != itarget.port_len) {
-			err = got_error(GOT_ERR_PRIVSEP_LEN);
-			goto done;
-		}
-	}
-
-	STAILQ_INSERT_TAIL(&gotd_session.notification_targets, target, entry);
-	target = NULL;
-done:
-	if (err)
-		free_notification_target(target);
-	return err;
-}
-
-static const struct got_error *
-recv_notification_target_http(struct imsg *imsg)
-{
-	const struct got_error *err = NULL;
-	struct gotd_imsg_notitfication_target_http itarget;
-	struct gotd_notification_target *target;
-	size_t datalen;
-
-	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
-	if (datalen < sizeof(itarget))
-		return got_error(GOT_ERR_PRIVSEP_LEN);
-	memcpy(&itarget, imsg->data, sizeof(itarget));
-
-	if (datalen != sizeof(itarget) + itarget.hostname_len +
-	    itarget.port_len + itarget.path_len + itarget.auth_len +
-	    itarget.hmac_len)
-		return got_error(GOT_ERR_PRIVSEP_LEN);
-
-	if (itarget.hostname_len == 0 || itarget.port_len == 0 ||
-	    itarget.path_len == 0)
-		return got_error(GOT_ERR_PRIVSEP_LEN);
-
-	target = calloc(1, sizeof(*target));
-	if (target == NULL)
-		return got_error_from_errno("calloc");
-
-	target->type = GOTD_NOTIFICATION_VIA_HTTP;
-
-	target->conf.http.tls = itarget.tls;
-
-	target->conf.http.hostname = strndup(imsg->data +
-	    sizeof(itarget), itarget.hostname_len);
-	if (target->conf.http.hostname == NULL) {
-		err = got_error_from_errno("strndup");
-		goto done;
-	}
-	if (strlen(target->conf.http.hostname) != itarget.hostname_len) {
-		err = got_error(GOT_ERR_PRIVSEP_LEN);
-		goto done;
-	}
-
-	target->conf.http.port = strndup(imsg->data + sizeof(itarget) +
-	    itarget.hostname_len, itarget.port_len);
-	if (target->conf.http.port == NULL) {
-		err = got_error_from_errno("strndup");
-		goto done;
-	}
-	if (strlen(target->conf.http.port) != itarget.port_len) {
-		err = got_error(GOT_ERR_PRIVSEP_LEN);
-		goto done;
-	}
-	
-	target->conf.http.path = strndup(imsg->data +
-	    sizeof(itarget) + itarget.hostname_len + itarget.port_len,
-	    itarget.path_len);
-	if (target->conf.http.path == NULL) {
-		err = got_error_from_errno("strndup");
-		goto done;
-	}
-	if (strlen(target->conf.http.path) != itarget.path_len) {
-		err = got_error(GOT_ERR_PRIVSEP_LEN);
-		goto done;
-	}
-
-	if (itarget.auth_len) {
-		target->conf.http.auth = strndup(imsg->data +
-		    sizeof(itarget) + itarget.hostname_len +
-		    itarget.port_len + itarget.path_len,
-		    itarget.auth_len);
-		if (target->conf.http.auth == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		if (strlen(target->conf.http.auth) != itarget.auth_len) {
-			err = got_error(GOT_ERR_PRIVSEP_LEN);
-			goto done;
-		}
-	}
-
-	if (itarget.hmac_len) {
-		target->conf.http.hmac = strndup(imsg->data +
-		    sizeof(itarget) + itarget.hostname_len +
-		    itarget.port_len + itarget.path_len +
-		    itarget.auth_len, itarget.hmac_len);
-		if (target->conf.http.hmac == NULL) {
-			err = got_error_from_errno("strndup");
-			goto done;
-		}
-		if (strlen(target->conf.http.hmac) != itarget.hmac_len) {
-			err = got_error(GOT_ERR_PRIVSEP_LEN);
-			goto done;
-		}
-	}
-
-	STAILQ_INSERT_TAIL(&gotd_session.notification_targets, target, entry);
-	target = NULL;
-done:
-	if (err)
-		free_notification_target(target);
-	return err;
 }
 
 static void
@@ -2097,12 +1863,28 @@ session_dispatch(int fd, short event, void *arg)
 				gotd_session.num_notification_refs_needed = 0;
 			}
 			break;
-		case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL:
-			err = recv_notification_target_email(&imsg);
-			break;
-		case GOTD_IMSG_NOTIFICATION_TARGET_HTTP:
-			err = recv_notification_target_http(&imsg);
+		case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL: {
+			struct gotd_notification_target *target;
+
+			err = gotd_imsg_recv_notification_target_email(NULL,
+			    &target, &imsg);
+			if (err)
+				break;
+			STAILQ_INSERT_TAIL(&gotd_session.notification_targets,
+			    target, entry);
 			break;
+		}
+		case GOTD_IMSG_NOTIFICATION_TARGET_HTTP: {
+			struct gotd_notification_target *target;
+
+			err = gotd_imsg_recv_notification_target_http(NULL,
+			    &target, &imsg);
+			if (err)
+				break;
+			STAILQ_INSERT_TAIL(&gotd_session.notification_targets,
+			    target, entry);
+			break;
+		}
 		case GOTD_IMSG_CONNECT_NOTIFIER:
 			err = recv_notifier(&imsg);
 			break;