int main() { volatile int i; trace_append("%s: setup FreeRTOS...\n", __func__); MboxQueue = xQueueCreate( 32, sizeof( unsigned int* ) ); vSemaphoreCreateBinary(InitDoneSemaphore); xSemaphoreTake(InitDoneSemaphore, portMAX_DELAY); hw_init(); xTaskCreate(LedFlash, "led", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL); xTaskCreate(IpcTask, "ipc", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); xTaskCreate(RdaemonTask, "rdaemon", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); trace_append("%s: start FreeRTOS...\n", __func__); vTaskStartScheduler(); /* Just sit and flash the LED quickly if we fail */ while( 1 ) { for( i = 0; i < 50000; i++ ); toggle_bit(GPIO_DATAOUT, 25); } }
static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt, DSN *dsn) { MSG_STATS stats; if (cleanup_trace_path == 0) { cleanup_trace_path = vstring_alloc(10); mail_queue_path(cleanup_trace_path, MAIL_QUEUE_TRACE, state->queue_id); } if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id, CLEANUP_MSG_STATS(&stats, state), rcpt, "none", dsn) != 0) { msg_warn("%s: trace logfile update error", state->queue_id); state->errs |= CLEANUP_STAT_WRITE; } }
void trace(unsigned int pc, unsigned int sp, unsigned int top) { //unsigned int *spalign = (unsigned int*)&_stack[0]; // if (pc < 0x40 || pc >=0x400) { /* if (sp > sizeof(_stack)) { printf("Access beyond end of stack 0x%08x\n",sp); fflush(stdout); abort(); } */ trace_append(pc,sp,top); /* printf("0x%07X 0x%02X 0x%08X 0x%08X 0x%08X 0x?u 0x%016x\n", pc, _memory[pc], sp, top, bswap_32(spalign[ (( ( sp & (STACK_SIZE-1) ) >>2) + 1 )] ), zpuino_get_tick_count() ); */ //fflush(stdout); // } }
int defer_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn) { const char *rcpt_domain; DSN my_dsn = *dsn; int status; /* * Sanity check. */ if (my_dsn.status[0] != '4' || !dsn_valid(my_dsn.status)) { msg_warn("defer_append: ignoring dsn code \"%s\"", my_dsn.status); my_dsn.status = "4.0.0"; } /* * MTA-requested address verification information is stored in the verify * service database. */ if (flags & DEL_REQ_FLAG_MTA_VRFY) { my_dsn.action = "undeliverable"; status = verify_append(id, stats, rcpt, relay, &my_dsn, DEL_RCPT_STAT_DEFER); return (status); } /* * User-requested address verification information is logged and mailed * to the requesting user. */ if (flags & DEL_REQ_FLAG_USR_VRFY) { my_dsn.action = "undeliverable"; status = trace_append(flags, id, stats, rcpt, relay, &my_dsn); return (status); } /* * Normal mail delivery. May also send a delivery record to the user. * * XXX DSN We write all deferred recipients to the defer logfile regardless * of DSN NOTIFY options, because those options don't apply to mailq(1) * reports or to postmaster notifications. */ else { /* * Supply default action. */ my_dsn.action = "delayed"; if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service, ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND, ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt, ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn, ATTR_TYPE_END) != 0) msg_warn("%s: %s service failure", id, var_defer_service); log_adhoc(id, stats, rcpt, relay, &my_dsn, "deferred"); /* * Traced delivery. */ if (flags & DEL_REQ_FLAG_RECORD) if (trace_append(flags, id, stats, rcpt, relay, &my_dsn) != 0) msg_warn("%s: %s service failure", id, var_trace_service); /* * Notify the fast flush service. XXX Should not this belong in the * bounce/defer daemon? Well, doing it here is more robust. */ if ((rcpt_domain = strrchr(rcpt->address, '@')) != 0 && *++rcpt_domain != 0) switch (flush_add(rcpt_domain, id)) { case FLUSH_STAT_OK: case FLUSH_STAT_DENY: break; default: msg_warn("%s: %s service failure", id, var_flush_service); break; } return (-1); } }
static void IpcTask (void * pvParameters) { unsigned int msg, *local_vq_buf; int ret; struct virtqueue_buf virtq_buf; portTickType LastWake; trace_append("%s: starting task\n", __func__); /* Workaround * * We can't enable interrupts in U-Boot. Let's wait until Linux is booted * on CPU. Linux remoteproc framework sends a ping to IPU via mailbox when * its initialization is completed. This ping is a good indicator for IPU * that Linux and its remoteproc/rpmsg subsystems are up an running. */ while (1) { msg = mailbox_read(); if (msg == HOST_ECHO_REQUEST) { trace_append("%s: received echo request [0x%x] from CPU\n", __func__, msg); break; } trace_append("%s: host-to-m3 mailbox [0x%x]\n", __func__, msg); LastWake = xTaskGetTickCount(); vTaskDelayUntil(&LastWake, 5000); } virtqueue_init(); nvic_enable_irq(MAILBOX_IRQ); enable_mailbox_irq(); trace_append("%s: start main loop\n", __func__); for (;;) { xQueueReceive(MboxQueue, &msg, portMAX_DELAY); switch(msg) { case RP_MBOX_ECHO_REQUEST : mailbox_send(M3_TO_HOST_MBX, RP_MBOX_ECHO_REPLY); break; case HOST_TO_M3_VRING : ret = virtqueue_get_avail_buf(&virtqueue_list[msg], &virtq_buf); /* make a local copy of the buffer */ local_vq_buf = pvPortMalloc(RP_MSG_BUF_SIZE); memcpy(local_vq_buf, virtq_buf.buf_ptr, RP_MSG_BUF_SIZE); virtqueue_add_used_buf(&virtqueue_list[msg], virtq_buf.head); /* dispatch to the service queue */ rpmsg_dispatch_msg(local_vq_buf); break; case M3_TO_HOST_VRING : xSemaphoreGive(InitDoneSemaphore); break; default: trace_append("%s: unknown message\n", __func__); break; } } vTaskDelete(NULL); }
int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, char *name, int *statusp) { const char *myname = "deliver_alias"; const char *alias_result; char *saved_alias_result; char *owner; char **cpp; uid_t alias_uid; struct mypasswd *alias_pwd; VSTRING *canon_owner; DICT *dict; const char *owner_rhs; /* owner alias, RHS */ int alias_count; int dsn_notify; char *dsn_envid; int dsn_ret; const char *dsn_orcpt; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * DUPLICATE/LOOP ELIMINATION * * We cannot do duplicate elimination here. Sendmail compatibility requires * that we allow multiple deliveries to the same alias, even recursively! * For example, we must deliver to mailbox any messags that are addressed * to the alias of a user that lists that same alias in her own .forward * file. Yuck! This is just an example of some really perverse semantics * that people will expect Postfix to implement just like sendmail. * * We can recognize one special case: when an alias includes its own name, * deliver to the user instead, just like sendmail. Otherwise, we just * bail out when nesting reaches some unreasonable depth, and blame it on * a possible alias loop. */ if (state.msg_attr.exp_from != 0 && strcasecmp(state.msg_attr.exp_from, name) == 0) return (NO); if (state.level > 100) { msg_warn("alias database loop for %s", name); dsb_simple(state.msg_attr.why, "5.4.6", "alias database loop for %s", name); *statusp = bounce_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); return (YES); } state.msg_attr.exp_from = name; /* * There are a bunch of roles that we're trying to keep track of. * * First, there's the issue of whose rights should be used when delivering * to "|command" or to /file/name. With alias databases, the rights are * those of who owns the alias, i.e. the database owner. With aliases * owned by root, a default user is used instead. When an alias with * default rights references an include file owned by an ordinary user, * we must use the rights of the include file owner, otherwise the * include file owner could take control of the default account. * * Secondly, there's the question of who to notify of delivery problems. * With aliases that have an owner- alias, the latter is used to set the * sender and owner attributes. Otherwise, the owner attribute is reset * (the alias is globally visible and could be sent to by anyone). */ for (cpp = alias_maps->argv->argv; *cpp; cpp++) { if ((dict = dict_handle(*cpp)) == 0) msg_panic("%s: dictionary not found: %s", myname, *cpp); if ((alias_result = dict_get(dict, name)) != 0) { if (msg_verbose) msg_info("%s: %s: %s = %s", myname, *cpp, name, alias_result); /* * Don't expand a verify-only request. */ if (state.request->flags & DEL_REQ_FLAG_MTA_VRFY) { dsb_simple(state.msg_attr.why, "2.0.0", "aliased to %s", alias_result); *statusp = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)); return (YES); } /* * DELIVERY POLICY * * Update the expansion type attribute, so we can decide if * deliveries to |command and /file/name are allowed at all. */ state.msg_attr.exp_type = EXPAND_TYPE_ALIAS; /* * DELIVERY RIGHTS * * What rights to use for |command and /file/name deliveries? The * command and file code will use default rights when the alias * database is owned by root, otherwise it will use the rights of * the alias database owner. */ if ((alias_uid = dict_owner(*cpp)) == 0) { alias_pwd = 0; RESET_USER_ATTR(usr_attr, state.level); } else { if ((alias_pwd = mypwuid(alias_uid)) == 0) { msg_warn("cannot find alias database owner for %s", *cpp); dsb_simple(state.msg_attr.why, "4.3.0", "cannot find alias database owner"); *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); return (YES); } SET_USER_ATTR(usr_attr, alias_pwd, state.level); } /* * WHERE TO REPORT DELIVERY PROBLEMS. * * Use the owner- alias if one is specified, otherwise reset the * owner attribute and use the include file ownership if we can. * Save the dict_lookup() result before something clobbers it. * * Don't match aliases that are based on regexps. */ #define OWNER_ASSIGN(own) \ (own = (var_ownreq_special == 0 ? 0 : \ concatenate("owner-", name, (char *) 0))) saved_alias_result = mystrdup(alias_result); if (OWNER_ASSIGN(owner) != 0 && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) { canon_owner = canon_addr_internal(vstring_alloc(10), var_exp_own_alias ? owner_rhs : owner); /* Set envelope sender and owner attribute. */ SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level); } else { canon_owner = 0; /* Note: this does not reset the envelope sender. */ if (var_reset_owner_attr) RESET_OWNER_ATTR(state.msg_attr, state.level); } /* * EXTERNAL LOOP CONTROL * * Set the delivered message attribute to the recipient, so that * this message will list the correct forwarding address. */ if (var_frozen_delivered == 0) state.msg_attr.delivered = state.msg_attr.rcpt.address; /* * Deliver. */ alias_count = 0; if (dict_errno != 0) { dsb_simple(state.msg_attr.why, "4.3.0", "alias database unavailable"); *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); } else { /* * XXX DSN * * When delivering to a mailing list (i.e. the envelope sender * is replaced) the ENVID, NOTIFY, RET, and ORCPT parameters * which accompany the redistributed message MUST NOT be * derived from those of the original message. * * When delivering to an alias (i.e. the envelope sender is not * replaced) any ENVID, RET, or ORCPT parameters are * propagated to all forwarding addresses associated with * that alias. The NOTIFY parameter is propagated to the * forwarding addresses, except that any SUCCESS keyword is * removed. */ #define DSN_SAVE_UPDATE(saved, old, new) do { \ saved = old; \ old = new; \ } while (0) DSN_SAVE_UPDATE(dsn_notify, state.msg_attr.rcpt.dsn_notify, dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER : dsn_notify & ~DSN_NOTIFY_SUCCESS); if (canon_owner != 0) { DSN_SAVE_UPDATE(dsn_envid, state.msg_attr.dsn_envid, ""); DSN_SAVE_UPDATE(dsn_ret, state.msg_attr.dsn_ret, 0); DSN_SAVE_UPDATE(dsn_orcpt, state.msg_attr.rcpt.dsn_orcpt, ""); state.msg_attr.rcpt.orig_addr = ""; } *statusp = deliver_token_string(state, usr_attr, saved_alias_result, &alias_count); #if 0 if (var_ownreq_special && strncmp("owner-", state.msg_attr.sender, 6) != 0 && alias_count > 10) msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias", name, name); #endif if (alias_count < 1) { msg_warn("no recipient in alias lookup result for %s", name); dsb_simple(state.msg_attr.why, "4.3.0", "alias database unavailable"); *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); } else { /* * XXX DSN * * When delivering to a mailing list (i.e. the envelope * sender address is replaced) and NOTIFY=SUCCESS was * specified, report a DSN of "delivered". * * When delivering to an alias (i.e. the envelope sender * address is not replaced) and NOTIFY=SUCCESS was * specified, report a DSN of "expanded". */ if (dsn_notify & DSN_NOTIFY_SUCCESS) { state.msg_attr.rcpt.dsn_notify = dsn_notify; if (canon_owner != 0) { state.msg_attr.dsn_envid = dsn_envid; state.msg_attr.dsn_ret = dsn_ret; state.msg_attr.rcpt.dsn_orcpt = dsn_orcpt; } dsb_update(state.msg_attr.why, "2.0.0", canon_owner ? "delivered" : "expanded", DSB_SKIP_RMTA, DSB_SKIP_REPLY, "alias expanded"); (void) trace_append(BOUNCE_FLAG_NONE, SENT_ATTR(state.msg_attr)); } } } myfree(saved_alias_result); if (owner) myfree(owner); if (canon_owner) vstring_free(canon_owner); if (alias_pwd) mypwfree(alias_pwd); return (YES); } /* * If the alias database was inaccessible for some reason, defer * further delivery for the current top-level recipient. */ if (dict_errno != 0) { dsb_simple(state.msg_attr.why, "4.3.0", "alias database unavailable"); *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); return (YES); } else { if (msg_verbose) msg_info("%s: %s: %s not found", myname, *cpp, name); } } /* * Try delivery to a local user instead. */ return (NO); }
int sent(int flags, const char *id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn) { DSN my_dsn = *dsn; int status; /* * Sanity check. */ if (my_dsn.status[0] != '2' || !dsn_valid(my_dsn.status)) { msg_warn("sent: ignoring dsn code \"%s\"", my_dsn.status); my_dsn.status = "2.0.0"; } /* * MTA-requested address verification information is stored in the verify * service database. */ if (flags & DEL_REQ_FLAG_MTA_VRFY) { my_dsn.action = "deliverable"; status = verify_append(id, stats, recipient, relay, &my_dsn, DEL_RCPT_STAT_OK); return (status); } /* * User-requested address verification information is logged and mailed * to the requesting user. */ if (flags & DEL_REQ_FLAG_USR_VRFY) { my_dsn.action = "deliverable"; status = trace_append(flags, id, stats, recipient, relay, &my_dsn); return (status); } /* * Normal mail delivery. May also send a delivery record to the user. */ else { if (my_dsn.action == 0 || my_dsn.action[0] == 0) my_dsn.action = "delivered"; if (((flags & DEL_REQ_FLAG_RECORD) == 0 || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0) && ((recipient->dsn_notify & DSN_NOTIFY_SUCCESS) == 0 || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)) { log_adhoc(id, stats, recipient, relay, &my_dsn, "sent"); status = 0; } else { VSTRING *junk = vstring_alloc(100); vstring_sprintf(junk, "%s: %s service failed", id, var_trace_service); my_dsn.reason = vstring_str(junk); my_dsn.status ="4.3.0"; status = defer_append(flags, id, stats, recipient, relay, &my_dsn); vstring_free(junk); } return (status); } }
int deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp) { const char *myname = "deliver_dotforward"; struct stat st; VSTRING *path; struct mypasswd *mypwd; int fd; VSTREAM *fp; int status; int forward_found = NO; int lookup_status; int addr_count; char *saved_forward_path; char *lhs; char *next; int expand_status; int saved_notify; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * Skip this module if per-user forwarding is disabled. */ if (*var_forward_path == 0) return (NO); /* * Skip non-existing users. The mailbox delivery routine will catch the * error. */ if ((errno = mypwnam_err(state.msg_attr.user, &mypwd)) != 0) { msg_warn("error looking up passwd info for %s: %m", state.msg_attr.user); dsb_simple(state.msg_attr.why, "4.0.0", "user lookup error"); *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); return (YES); } if (mypwd == 0) return (NO); /* * From here on no early returns or we have a memory leak. */ /* * EXTERNAL LOOP CONTROL * * Set the delivered message attribute to the recipient, so that this * message will list the correct forwarding address. */ if (var_frozen_delivered == 0) state.msg_attr.delivered = state.msg_attr.rcpt.address; /* * DELIVERY RIGHTS * * Do not inherit rights from the .forward file owner. Instead, use the * recipient's rights, and insist that the .forward file is owned by the * recipient. This is a small but significant difference. Use the * recipient's rights for all /file and |command deliveries, and pass on * these rights to command/file destinations in included files. When * these are the rights of root, the /file and |command delivery routines * will use unprivileged default rights instead. Better safe than sorry. */ SET_USER_ATTR(usr_attr, mypwd, state.level); /* * DELIVERY POLICY * * Update the expansion type attribute so that we can decide if deliveries * to |command and /file/name are allowed at all. */ state.msg_attr.exp_type = EXPAND_TYPE_FWD; /* * WHERE TO REPORT DELIVERY PROBLEMS * * Set the owner attribute so that 1) include files won't set the sender to * be this user and 2) mail forwarded to other local users will be * resubmitted as a new queue file. */ state.msg_attr.owner = state.msg_attr.user; /* * Search the forward_path for an existing forward file. * * If unmatched extensions should never be propagated, or if a forward file * name includes the address extension, don't propagate the extension to * the recipient addresses. */ status = 0; path = vstring_alloc(100); saved_forward_path = mystrdup(var_forward_path); next = saved_forward_path; lookup_status = -1; while ((lhs = mystrtok(&next, ", \t\r\n")) != 0) { expand_status = local_expand(path, lhs, &state, &usr_attr, var_fwd_exp_filter); if ((expand_status & (MAC_PARSE_ERROR | MAC_PARSE_UNDEF)) == 0) { lookup_status = lstat_as(STR(path), &st, usr_attr.uid, usr_attr.gid); if (msg_verbose) msg_info("%s: path %s expand_status %d look_status %d", myname, STR(path), expand_status, lookup_status); if (lookup_status >= 0) { if ((expand_status & LOCAL_EXP_EXTENSION_MATCHED) != 0 || (local_ext_prop_mask & EXT_PROP_FORWARD) == 0) state.msg_attr.unmatched = 0; break; } } } /* * Process the forward file. * * Assume that usernames do not have file system meta characters. Open the * .forward file as the user. Ignore files that aren't regular files, * files that are owned by the wrong user, or files that have world write * permission enabled. * * DUPLICATE/LOOP ELIMINATION * * If this user includes (an alias of) herself in her own .forward file, * deliver to the user instead. */ if (lookup_status >= 0) { /* * Don't expand a verify-only request. */ if (state.request->flags & DEL_REQ_FLAG_MTA_VRFY) { dsb_simple(state.msg_attr.why, "2.0.0", "forward via file: %s", STR(path)); *statusp = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)); forward_found = YES; } else if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) { state.msg_attr.exp_from = state.msg_attr.local; if (S_ISREG(st.st_mode) == 0) { msg_warn("file %s is not a regular file", STR(path)); } else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) { msg_warn("file %s has bad owner uid %ld", STR(path), (long) st.st_uid); } else if (st.st_mode & 002) { msg_warn("file %s is world writable", STR(path)); } else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) { msg_warn("cannot open file %s: %m", STR(path)); } else { /* * XXX DSN. When delivering to an alias (i.e. the envelope * sender address is not replaced) any ENVID, RET, or ORCPT * parameters are propagated to all forwarding addresses * associated with that alias. The NOTIFY parameter is * propagated to the forwarding addresses, except that any * SUCCESS keyword is removed. */ close_on_exec(fd, CLOSE_ON_EXEC); addr_count = 0; fp = vstream_fdopen(fd, O_RDONLY); saved_notify = state.msg_attr.rcpt.dsn_notify; state.msg_attr.rcpt.dsn_notify = (saved_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER : saved_notify & ~DSN_NOTIFY_SUCCESS); status = deliver_token_stream(state, usr_attr, fp, &addr_count); if (vstream_fclose(fp)) msg_warn("close file %s: %m", STR(path)); if (addr_count > 0) { forward_found = YES; been_here(state.dup_filter, "forward-done %s", STR(path)); /* * XXX DSN. When delivering to an alias (i.e. the * envelope sender address is not replaced) and the * original NOTIFY parameter for the alias contained the * SUCCESS keyword, an "expanded" DSN is issued for the * alias. */ if (status == 0 && (saved_notify & DSN_NOTIFY_SUCCESS)) { state.msg_attr.rcpt.dsn_notify = saved_notify; dsb_update(state.msg_attr.why, "2.0.0", "expanded", DSB_SKIP_RMTA, DSB_SKIP_REPLY, "alias expanded"); (void) trace_append(BOUNCE_FLAG_NONE, SENT_ATTR(state.msg_attr)); } } } } else if (been_here_check(state.dup_filter, "forward-done %s", STR(path)) != 0) forward_found = YES; /* else we're recursive */ } /* * Clean up. */ vstring_free(path); myfree(saved_forward_path); mypwfree(mypwd); *statusp = status; return (forward_found); }
int sent(int flags, const char *id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn) { const char *myname="sent.c Sent"; if (msg_verbose) msg_info("HU--%s Starting",myname); DSN my_dsn = *dsn; DSN *dsn_res; int status; /* * Sanity check. */ if (my_dsn.status[0] != '2' || !dsn_valid(my_dsn.status)) { msg_warn("sent: ignoring dsn code \"%s\"", my_dsn.status); my_dsn.status = "2.0.0"; } /* * DSN filter (Postfix 3.0). */ if (delivery_status_filter != 0 && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0) my_dsn = *dsn_res; /* * MTA-requested address verification information is stored in the verify * service database. */ if (flags & DEL_REQ_FLAG_MTA_VRFY) { my_dsn.action = "deliverable"; status = verify_append(id, stats, recipient, relay, &my_dsn, DEL_RCPT_STAT_OK); return (status); } /* * User-requested address verification information is logged and mailed * to the requesting user. */ if (flags & DEL_REQ_FLAG_USR_VRFY) { my_dsn.action = "deliverable"; status = trace_append(flags, id, stats, recipient, relay, &my_dsn); return (status); } /* * Normal mail delivery. May also send a delivery record to the user. */ else { /* Readability macros: record all deliveries, or the delayed ones. */ #define REC_ALL_SENT(flags) (flags & DEL_REQ_FLAG_RECORD) #define REC_DLY_SENT(flags, rcpt) \ ((flags & DEL_REQ_FLAG_REC_DLY_SENT) \ && (rcpt->dsn_notify == 0 || (rcpt->dsn_notify & DSN_NOTIFY_DELAY))) if (my_dsn.action == 0 || my_dsn.action[0] == 0) my_dsn.action = "delivered"; if (((REC_ALL_SENT(flags) == 0 && REC_DLY_SENT(flags, recipient) == 0) || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0) && ((recipient->dsn_notify & DSN_NOTIFY_SUCCESS) == 0 || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)) { log_adhoc(id, stats, recipient, relay, &my_dsn, "sent"); status = 0; } else { VSTRING *junk = vstring_alloc(100); vstring_sprintf(junk, "%s: %s service failed", id, var_trace_service); my_dsn.reason = vstring_str(junk); my_dsn.status = "4.3.0"; status = defer_append(flags, id, stats, recipient, relay, &my_dsn); vstring_free(junk); } return (status); } }
int bounce_one_intern(int flags, const char *queue, const char *id, const char *encoding, const char *sender, const char *dsn_envid, int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn) { DSN my_dsn = *dsn; int status; /* * MTA-requested address verification information is stored in the verify * service database. */ if (flags & DEL_REQ_FLAG_MTA_VRFY) { my_dsn.action = "undeliverable"; status = verify_append(id, stats, rcpt, relay, &my_dsn, DEL_RCPT_STAT_BOUNCE); return (status); } /* * User-requested address verification information is logged and mailed * to the requesting user. */ if (flags & DEL_REQ_FLAG_USR_VRFY) { my_dsn.action = "undeliverable"; status = trace_append(flags, id, stats, rcpt, relay, &my_dsn); return (status); } /* * When we're not bouncing, then use the standard multi-recipient logfile * based procedure. */ else if (var_soft_bounce) { return (bounce_append_intern(flags, id, stats, rcpt, relay, &my_dsn)); } /* * Normal mail delivery. May also send a delivery record to the user. * * XXX DSN We send all recipients regardless of DSN NOTIFY options, because * those options don't apply to postmaster notifications. */ else { /* * Supply default action. */ my_dsn.action = "failed"; if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service, ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE, ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret, ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt, ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn, ATTR_TYPE_END) == 0 && ((flags & DEL_REQ_FLAG_RECORD) == 0 || trace_append(flags, id, stats, rcpt, relay, &my_dsn) == 0)) { log_adhoc(id, stats, rcpt, relay, &my_dsn, "bounced"); status = 0; } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { VSTRING *junk = vstring_alloc(100); my_dsn.status = "4.3.0"; vstring_sprintf(junk, "%s or %s service failure", var_bounce_service, var_trace_service); my_dsn.reason = vstring_str(junk); status = defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn); vstring_free(junk); } else { status = -1; } return (status); } }
int bounce_append_intern(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn) { DSN my_dsn = *dsn; int status; /* * MTA-requested address verification information is stored in the verify * service database. */ if (flags & DEL_REQ_FLAG_MTA_VRFY) { my_dsn.action = "undeliverable"; status = verify_append(id, stats, rcpt, relay, &my_dsn, DEL_RCPT_STAT_BOUNCE); return (status); } /* * User-requested address verification information is logged and mailed * to the requesting user. */ if (flags & DEL_REQ_FLAG_USR_VRFY) { my_dsn.action = "undeliverable"; status = trace_append(flags, id, stats, rcpt, relay, &my_dsn); return (status); } /* * Normal (well almost) delivery. When we're pretending that we can't * bounce, don't create a defer log file when we wouldn't keep the bounce * log file. That's a lot of negatives in one sentence. */ else if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN)) { return (-1); } /* * Normal mail delivery. May also send a delivery record to the user. * * XXX DSN We write all recipients to the bounce logfile regardless of DSN * NOTIFY options, because those options don't apply to postmaster * notifications. */ else { char *my_status = mystrdup(my_dsn.status); const char *log_status = var_soft_bounce ? "SOFTBOUNCE" : "bounced"; /* * Supply default action. */ my_dsn.status = my_status; if (var_soft_bounce) { my_status[0] = '4'; my_dsn.action = "delayed"; } else { my_dsn.action = "failed"; } if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ? var_defer_service : var_bounce_service, ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND, ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt, ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn, ATTR_TYPE_END) == 0 && ((flags & DEL_REQ_FLAG_RECORD) == 0 || trace_append(flags, id, stats, rcpt, relay, &my_dsn) == 0)) { log_adhoc(id, stats, rcpt, relay, &my_dsn, log_status); status = (var_soft_bounce ? -1 : 0); } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { VSTRING *junk = vstring_alloc(100); my_dsn.status = "4.3.0"; vstring_sprintf(junk, "%s or %s service failure", var_bounce_service, var_trace_service); my_dsn.reason = vstring_str(junk); status = defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn); vstring_free(junk); } else { status = -1; } myfree(my_status); return (status); } }