int post_mail_fputs(VSTREAM *cleanup, const char *str) { ssize_t len = str ? strlen(str) : 0; return (rec_put(cleanup, REC_TYPE_NORM, str, len) != REC_TYPE_NORM ? CLEANUP_STAT_WRITE : 0); }
static int smtpd_proxy_save_rec_put(VSTREAM *stream, int rec_type, const char *data, ssize_t len) { const char *myname = "smtpd_proxy_save_rec_put"; int ret; #define VSTREAM_TO_SMTPD_STATE(s) ((SMTPD_STATE *) vstream_context(s)) /* * Sanity check. */ if (stream == 0) msg_panic("%s: attempt to use closed stream", myname); /* * Send one content record. Errors and results must be as with rec_put(). */ if (rec_type == REC_TYPE_NORM || rec_type == REC_TYPE_CONT) ret = rec_put(stream, rec_type, data, len); else msg_panic("%s: need REC_TYPE_NORM or REC_TYPE_CONT", myname); /* * Errors last. */ if (ret != rec_type) { (void) smtpd_proxy_replay_rdwr_error(VSTREAM_TO_SMTPD_STATE(stream)); return (REC_TYPE_ERROR); } return (rec_type); }
static void output_text(void *context, int rec_type, const char *buf, ssize_t len, off_t unused_offset) { SM_STATE *state = (SM_STATE *) context; if (rec_put(state->dst, rec_type, buf, len) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", state->saved_sender, (long) state->uid); }
void expire_item() { int pos, pos1, fd; char fgrp[80], fitem[80], fname[80], fold[80], fnew[80]; time_t expire; SLOT grp, item; expire = time(0) - EXP * 86400; pos = pos1 = 0; sprintf(fgrp, "2nd/%s", FN_GRP); while(rec_get(fgrp, &grp, sizeof(SLOT), pos) != -1) { sprintf(fitem, "2nd/%s/%s", grp.fn, FN_ITEM); sprintf(fnew, "2nd/%s/%s.new", grp.fn, FN_ITEM); fd = open(fnew, O_CREAT | O_TRUNC, 0600); // touch a new file if(fd > 0) close(fd); fd = 0; while(rec_get(fitem, &item, sizeof(SLOT), pos1) != -1) { if((item.prop & PROP_I_CANCEL) || (item.chrono < expire)) { sprintf(fname, "2nd/%s/%c/%s", grp.fn, item.fn[7], item.fn); f_rm(fname); } else { fd++; rec_add(fnew, &item, sizeof(SLOT)); } pos1++; } sprintf(fold, "2nd/%s/%s.old", grp.fn, FN_ITEM); f_cp(fitem, fold, O_TRUNC); f_mv(fnew, fitem); grp.reply = fd; rec_put(fgrp, &grp, sizeof(SLOT), pos); pos++; } return; }
static void qmqpd_copy_sender(QMQPD_STATE *state) { char *end_prefix; char *end_origin; int verp_requested; static char verp_delims[] = "-="; /* * If the sender address looks like prefix@origin-@[], then request * variable envelope return path delivery, with an envelope sender * address of prefi@origin, and with VERP delimiters of x and =. This * way, the recipients will see envelope sender addresses that look like: * prefixuser=domain@origin. */ state->where = "receiving sender address"; netstring_get(state->client, state->buf, var_line_limit); VSTRING_TERMINATE(state->buf); verp_requested = ((end_origin = vstring_end(state->buf) - 4) > STR(state->buf) && strcmp(end_origin, "-@[]") == 0 && (end_prefix = strchr(STR(state->buf), '@')) != 0 /* XXX */ && --end_prefix < end_origin - 2 /* non-null origin */ && end_prefix > STR(state->buf)); /* non-null prefix */ if (verp_requested) { verp_delims[0] = end_prefix[0]; if (verp_delims_verify(verp_delims) != 0) { state->err |= CLEANUP_STAT_CONT; /* XXX */ vstring_sprintf(state->why_rejected, "Invalid VERP delimiters: \"%s\". Need two characters from \"%s\"", verp_delims, var_verp_filter); } memmove(end_prefix, end_prefix + 1, end_origin - end_prefix - 1); vstring_truncate(state->buf, end_origin - STR(state->buf) - 1); } if (state->err == CLEANUP_STAT_OK && REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0) state->err = CLEANUP_STAT_WRITE; if (verp_requested) if (state->err == CLEANUP_STAT_OK && rec_put(state->cleanup, REC_TYPE_VERP, verp_delims, 2) < 0) state->err = CLEANUP_STAT_WRITE; state->sender = mystrndup(STR(state->buf), LEN(state->buf)); }
int main() { char c; int usernum = 0, avgmoney = 0; long long int totalmoney = 0; FILE *fp; ECONOMY economy; long long int moneydiff = 0; double avgmoneydiff, days; time_t now_time, interval; chdir(BBSHOME); /* 第一次統計 */ if (rec_get(FN_ECONOMY, &economy, sizeof(ECONOMY), 0)) memset(&economy, 0, sizeof(ECONOMY)); for (c = 'a'; c <= 'z'; c++) { char buf[64]; struct dirent *de; DIR *dirp; sprintf(buf, BBSHOME "/usr/%c", c); chdir(buf); if (!(dirp = opendir("."))) continue; while (de = readdir(dirp)) { ACCT acct; int fd; char *fname; fname = de->d_name; if (*fname <= ' ' || *fname == '.') continue; sprintf(buf, "%s/.ACCT", fname); if ((fd = open(buf, O_RDONLY)) < 0) continue; read(fd, &acct, sizeof(ACCT)); close(fd); totalmoney += acct.money; usernum++; } closedir(dirp); } chdir(BBSHOME); avgmoney = totalmoney / usernum; now_time = time(0); interval = now_time - economy.last_time; days = (double) interval / (double) 86400; moneydiff = totalmoney - economy.totalmoney; avgmoneydiff = ((double) moneydiff / (double) usernum) / days; if (fp = fopen(OUTFILE_ECONOMY, "w")) { fprintf(fp, "\n\n\t\t\t\t\t本站經濟概況\n"); fprintf(fp, "\n\t\t╭─┤\033[1;32;41m %s \033[m├─╮\n", Now()); fprintf(fp, "\t\t│本站目前總人口:%14d 人 │\n", usernum); fprintf(fp, "\t\t│\033[1m本站人民總銀幣:%14lld 元\033[m │\n", totalmoney); fprintf(fp, "\t\t│\033[1m平均每人有銀幣:%14d 元\033[m │\n", avgmoney); fprintf(fp, "\t\t│\033[1m銀幣日生產毛額:%14lld 元\033[m │\n", moneydiff); fprintf(fp, "\t\t│\033[1m平均銀幣日產額:%14.3f 元\033[m │\n", avgmoneydiff); fprintf(fp, "\t\t╰─────────────────╯\n"); fclose(fp); } economy.totalmoney = totalmoney; economy.last_time = now_time; rec_put(FN_ECONOMY, &economy, sizeof(ECONOMY), 0, NULL); }
static void enqueue(const int flags, const char *encoding, const char *dsn_envid, int dsn_ret, int dsn_notify, const char *rewrite_context, const char *sender, const char *full_name, char **recipients) { VSTRING *buf; VSTREAM *dst; char *saved_sender; char **cpp; int type; char *start; int skip_from_; TOK822 *tree; TOK822 *tp; int rcpt_count = 0; enum { STRIP_CR_DUNNO, STRIP_CR_DO, STRIP_CR_DONT, STRIP_CR_ERROR } strip_cr; MAIL_STREAM *handle; VSTRING *postdrop_command; uid_t uid = getuid(); int status; int naddr; int prev_type; MIME_STATE *mime_state = 0; SM_STATE state; int mime_errs; const char *errstr; int addr_count; int level; static NAME_CODE sm_fix_eol_table[] = { SM_FIX_EOL_ALWAYS, STRIP_CR_DO, SM_FIX_EOL_STRICT, STRIP_CR_DUNNO, SM_FIX_EOL_NEVER, STRIP_CR_DONT, 0, STRIP_CR_ERROR, }; /* * Access control is enforced in the postdrop command. The code here * merely produces a more user-friendly interface. */ if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl, uid)) != 0) msg_fatal_status(EX_NOPERM, "User %s(%ld) is not allowed to submit mail", errstr, (long) uid); /* * Initialize. */ buf = vstring_alloc(100); /* * Stop run-away process accidents by limiting the queue file size. This * is not a defense against DOS attack. */ if (var_message_limit > 0 && get_file_limit() > var_message_limit) set_file_limit((off_t) var_message_limit); /* * The sender name is provided by the user. In principle, the mail pickup * service could deduce the sender name from queue file ownership, but: * pickup would not be able to run chrooted, and it may not be desirable * to use login names at all. */ if (sender != 0) { VSTRING_RESET(buf); VSTRING_TERMINATE(buf); tree = tok822_parse(sender); for (naddr = 0, tp = tree; tp != 0; tp = tp->next) if (tp->type == TOK822_ADDR && naddr++ == 0) tok822_internalize(buf, tp->head, TOK822_STR_DEFL); tok822_free_tree(tree); saved_sender = mystrdup(STR(buf)); if (naddr > 1) msg_warn("-f option specified malformed sender: %s", sender); } else { if ((sender = username()) == 0) msg_fatal_status(EX_OSERR, "no login name found for user ID %lu", (unsigned long) uid); saved_sender = mystrdup(sender); } /* * Let the postdrop command open the queue file for us, and sanity check * the content. XXX Make postdrop a manifest constant. */ errno = 0; postdrop_command = vstring_alloc(1000); vstring_sprintf(postdrop_command, "%s/postdrop -r", var_command_dir); for (level = 0; level < msg_verbose; level++) vstring_strcat(postdrop_command, " -v"); if ((handle = mail_stream_command(STR(postdrop_command))) == 0) msg_fatal_status(EX_UNAVAILABLE, "%s(%ld): unable to execute %s: %m", saved_sender, (long) uid, STR(postdrop_command)); vstring_free(postdrop_command); dst = handle->stream; /* * First, write envelope information to the output stream. * * For sendmail compatibility, parse each command-line recipient as if it * were an RFC 822 message header; some MUAs specify comma-separated * recipient lists; and some MUAs even specify "word word <address>". * * Sort-uniq-ing the recipient list is done after address canonicalization, * before recipients are written to queue file. That's cleaner than * having the queue manager nuke duplicate recipient status records. * * XXX Should limit the size of envelope records. * * With "sendmail -N", instead of a per-message NOTIFY record we store one * per recipient so that we can simplify the implementation somewhat. */ if (dsn_envid) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_DSN_ENVID, dsn_envid); if (dsn_ret) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_RET, dsn_ret); rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_RWR_CONTEXT, rewrite_context); if (full_name || (full_name = fullname()) != 0) rec_fputs(dst, REC_TYPE_FULL, full_name); rec_fputs(dst, REC_TYPE_FROM, saved_sender); if (verp_delims && *saved_sender == 0) msg_fatal_status(EX_USAGE, "%s(%ld): -V option requires non-null sender address", saved_sender, (long) uid); if (encoding) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ENCODING, encoding); if (DEL_REQ_TRACE_FLAGS(flags)) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_TRACE_FLAGS, DEL_REQ_TRACE_FLAGS(flags)); if (verp_delims) rec_fputs(dst, REC_TYPE_VERP, verp_delims); if (recipients) { for (cpp = recipients; *cpp != 0; cpp++) { tree = tok822_parse(*cpp); for (addr_count = 0, tp = tree; tp != 0; tp = tp->next) { if (tp->type == TOK822_ADDR) { tok822_internalize(buf, tp->head, TOK822_STR_DEFL); if (dsn_notify) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); if (REC_PUT_BUF(dst, REC_TYPE_RCPT, buf) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); ++rcpt_count; ++addr_count; } } tok822_free_tree(tree); if (addr_count == 0) { if (rec_put(dst, REC_TYPE_RCPT, "", 0) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); ++rcpt_count; } } } /* * Append the message contents to the queue file. Write chunks of at most * 1kbyte. Internally, we use different record types for data ending in * LF and for data that doesn't, so we can actually be binary transparent * for local mail. Unfortunately, SMTP has no record continuation * convention, so there is no guarantee that arbitrary data will be * delivered intact via SMTP. Strip leading From_ lines. For the benefit * of UUCP environments, also get rid of leading >>>From_ lines. */ rec_fputs(dst, REC_TYPE_MESG, ""); if (DEL_REQ_TRACE_ONLY(flags) != 0) { if (flags & SM_FLAG_XRCPT) msg_fatal_status(EX_USAGE, "%s(%ld): -t option cannot be used with -bv", saved_sender, (long) uid); if (*saved_sender) rec_fprintf(dst, REC_TYPE_NORM, "From: %s", saved_sender); rec_fprintf(dst, REC_TYPE_NORM, "Subject: probe"); if (recipients) { rec_fprintf(dst, REC_TYPE_CONT, "To:"); for (cpp = recipients; *cpp != 0; cpp++) { rec_fprintf(dst, REC_TYPE_NORM, " %s%s", *cpp, cpp[1] ? "," : ""); } } } else { /* * Initialize the MIME processor and set up the callback context. */ if (flags & SM_FLAG_XRCPT) { state.dst = dst; state.recipients = argv_alloc(2); state.resent_recip = argv_alloc(2); state.resent = 0; state.saved_sender = saved_sender; state.uid = uid; state.temp = vstring_alloc(10); mime_state = mime_state_alloc(MIME_OPT_DISABLE_MIME | MIME_OPT_REPORT_TRUNC_HEADER, output_header, (MIME_STATE_ANY_END) 0, output_text, (MIME_STATE_ANY_END) 0, (MIME_STATE_ERR_PRINT) 0, (void *) &state); } /* * Process header/body lines. */ skip_from_ = 1; strip_cr = name_code(sm_fix_eol_table, NAME_CODE_FLAG_STRICT_CASE, var_sm_fix_eol); if (strip_cr == STRIP_CR_ERROR) msg_fatal_status(EX_USAGE, "invalid %s value: %s", VAR_SM_FIX_EOL, var_sm_fix_eol); for (prev_type = 0; (type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit)) != REC_TYPE_EOF; prev_type = type) { if (strip_cr == STRIP_CR_DUNNO && type == REC_TYPE_NORM) { if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r') strip_cr = STRIP_CR_DO; else strip_cr = STRIP_CR_DONT; } if (skip_from_) { if (type == REC_TYPE_NORM) { start = STR(buf); if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) continue; } skip_from_ = 0; } if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM) while (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r') vstring_truncate(buf, VSTRING_LEN(buf) - 1); if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT && VSTRING_LEN(buf) == 1 && *STR(buf) == '.') break; if (mime_state) { mime_errs = mime_state_update(mime_state, type, STR(buf), VSTRING_LEN(buf)); if (mime_errs) msg_fatal_status(EX_DATAERR, "%s(%ld): unable to extract recipients: %s", saved_sender, (long) uid, mime_state_error(mime_errs)); } else { if (REC_PUT_BUF(dst, type, buf) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); } } } /* * Finish MIME processing. We need a final mime_state_update() call in * order to flush text that is still buffered. That can happen when the * last line did not end in newline. */ if (mime_state) { mime_errs = mime_state_update(mime_state, REC_TYPE_EOF, "", 0); if (mime_errs) msg_fatal_status(EX_DATAERR, "%s(%ld): unable to extract recipients: %s", saved_sender, (long) uid, mime_state_error(mime_errs)); mime_state = mime_state_free(mime_state); } /* * Append recipient addresses that were extracted from message headers. */ rec_fputs(dst, REC_TYPE_XTRA, ""); if (flags & SM_FLAG_XRCPT) { for (cpp = state.resent ? state.resent_recip->argv : state.recipients->argv; *cpp; cpp++) { if (dsn_notify) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); if (rec_put(dst, REC_TYPE_RCPT, *cpp, strlen(*cpp)) < 0) msg_fatal_status(EX_TEMPFAIL, "%s(%ld): error writing queue file: %m", saved_sender, (long) uid); ++rcpt_count; } argv_free(state.recipients); argv_free(state.resent_recip); vstring_free(state.temp); } if (rcpt_count == 0) msg_fatal_status(EX_USAGE, (flags & SM_FLAG_XRCPT) ? "%s(%ld): No recipient addresses found in message header" : "%s(%ld): Recipient addresses must be specified on" " the command line or via the -t option", saved_sender, (long) uid); /* * Identify the end of the queue file. */ rec_fputs(dst, REC_TYPE_END, ""); /* * Make sure that the message makes it to the file system. Once we have * terminated with successful exit status we cannot lose the message due * to "frivolous reasons". If all goes well, prevent the run-time error * handler from removing the file. */ if (vstream_ferror(VSTREAM_IN)) msg_fatal_status(EX_DATAERR, "%s(%ld): error reading input: %m", saved_sender, (long) uid); if ((status = mail_stream_finish(handle, (VSTRING *) 0)) != 0) msg_fatal_status((status & CLEANUP_STAT_BAD) ? EX_SOFTWARE : (status & CLEANUP_STAT_WRITE) ? EX_TEMPFAIL : EX_UNAVAILABLE, "%s(%ld): %s", saved_sender, (long) uid, cleanup_strerror(status)); /* * Don't leave them in the dark. */ if (DEL_REQ_TRACE_FLAGS(flags)) { vstream_printf("Mail Delivery Status Report will be mailed to <%s>.\n", saved_sender); vstream_fflush(VSTREAM_OUT); } /* * Cleanup. Not really necessary as we're about to exit, but good for * debugging purposes. */ vstring_free(buf); myfree(saved_sender); }
static void qmqpd_write_content(QMQPD_STATE *state) { char *start; char *next; int len; int rec_type; int first = 1; int ch; /* * Start the message content segment. Prepend our own Received: header to * the message content. List the recipient only when a message has one * recipient. Otherwise, don't list the recipient to avoid revealing Bcc: * recipients that are supposed to be invisible. */ rec_fputs(state->cleanup, REC_TYPE_MESG, ""); rec_fprintf(state->cleanup, REC_TYPE_NORM, "Received: from %s (%s [%s])", state->name, state->name, state->rfc_addr); if (state->rcpt_count == 1 && state->recipient) { rec_fprintf(state->cleanup, REC_TYPE_NORM, "\tby %s (%s) with %s id %s", var_myhostname, var_mail_name, state->protocol, state->queue_id); quote_822_local(state->buf, state->recipient); rec_fprintf(state->cleanup, REC_TYPE_NORM, "\tfor <%s>; %s", STR(state->buf), mail_date(state->arrival_time.tv_sec)); } else { rec_fprintf(state->cleanup, REC_TYPE_NORM, "\tby %s (%s) with %s", var_myhostname, var_mail_name, state->protocol); rec_fprintf(state->cleanup, REC_TYPE_NORM, "\tid %s; %s", state->queue_id, mail_date(state->arrival_time.tv_sec)); } #ifdef RECEIVED_ENVELOPE_FROM quote_822_local(state->buf, state->sender); rec_fprintf(state->cleanup, REC_TYPE_NORM, "\t(envelope-from <%s>)", STR(state->buf)); #endif /* * Write the message content. * * XXX Force an empty record when the queue file content begins with * whitespace, so that it won't be considered as being part of our own * Received: header. What an ugly Kluge. * * XXX Deal with UNIX-style From_ lines at the start of message content just * in case. */ for (next = STR(state->message); /* void */ ; /* void */ ) { if ((ch = qmqpd_next_line(state->message, &start, &len, &next)) < 0) break; if (ch == '\n') rec_type = REC_TYPE_NORM; else rec_type = REC_TYPE_CONT; if (first) { if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) { rec_fprintf(state->cleanup, rec_type, "X-Mailbox-Line: %.*s", len, start); continue; } first = 0; if (len > 0 && IS_SPACE_TAB(start[0])) rec_put(state->cleanup, REC_TYPE_NORM, "", 0); } if (rec_put(state->cleanup, rec_type, start, len) < 0) { state->err = CLEANUP_STAT_WRITE; return; } } }
static int smtpd_proxy_replay_send(SMTPD_STATE *state) { const char *myname = "smtpd_proxy_replay_send"; static VSTRING *replay_buf = 0; SMTPD_PROXY *proxy = state->proxy; int rec_type; int expect = SMTPD_PROX_WANT_BAD; /* * Sanity check. */ if (smtpd_proxy_replay_stream == 0) msg_panic("%s: no before-queue filter speed-adjust log", myname); /* * Errors first. */ if (vstream_ferror(smtpd_proxy_replay_stream) || vstream_feof(smtpd_proxy_replay_stream) || rec_put(smtpd_proxy_replay_stream, REC_TYPE_END, "", 0) != REC_TYPE_END || vstream_fflush(smtpd_proxy_replay_stream)) /* NOT: fsync(vstream_fileno(smtpd_proxy_replay_stream)) */ return (smtpd_proxy_replay_rdwr_error(state)); /* * Delayed connection to the before-queue filter. */ if (smtpd_proxy_connect(state) < 0) return (-1); /* * Replay the speed-match log. We do sanity check record content, but we * don't implement a protocol state engine here, since we are reading * from a file that we just wrote ourselves. * * This is different than the MailChannels patented solution that * multiplexes a large number of slowed-down inbound connections over a * small number of fast connections to a local MTA. * * - MailChannels receives mail directly from the Internet. It uses one * connection to the local MTA to reject invalid recipients before * receiving the entire email message at reduced bit rates, and then uses * a different connection to quickly deliver the message to the local * MTA. * * - Postfix receives mail directly from the Internet. The Postfix SMTP * server rejects invalid recipients before receiving the entire message * over the Internet, and then delivers the message quickly to a local * SMTP-based content filter. */ if (replay_buf == 0) replay_buf = vstring_alloc(100); if (vstream_fseek(smtpd_proxy_replay_stream, (off_t) 0, SEEK_SET) < 0) return (smtpd_proxy_replay_rdwr_error(state)); for (;;) { switch (rec_type = rec_get(smtpd_proxy_replay_stream, replay_buf, REC_FLAG_NONE)) { /* * Message content. */ case REC_TYPE_NORM: case REC_TYPE_CONT: if (smtpd_proxy_rec_put(proxy->service_stream, rec_type, STR(replay_buf), LEN(replay_buf)) < 0) return (-1); break; /* * Expected server reply type. */ case REC_TYPE_RCPT: if (!alldig(STR(replay_buf)) || (expect = atoi(STR(replay_buf))) == SMTPD_PROX_WANT_BAD) msg_panic("%s: malformed server reply type: %s", myname, STR(replay_buf)); break; /* * Client command, or void. Bail out on the first negative proxy * response. This is OK, because the filter must use the same * reply code for all recipients of a multi-recipient message. */ case REC_TYPE_FROM: if (expect == SMTPD_PROX_WANT_BAD) msg_panic("%s: missing server reply type", myname); if (smtpd_proxy_cmd(state, expect, *STR(replay_buf) ? "%s" : SMTPD_PROXY_CONN_FMT, STR(replay_buf)) < 0) return (-1); expect = SMTPD_PROX_WANT_BAD; break; /* * Explicit end marker, instead of implicit EOF. */ case REC_TYPE_END: return (0); /* * Errors. */ case REC_TYPE_ERROR: return (smtpd_proxy_replay_rdwr_error(state)); default: msg_panic("%s: unexpected record type; %d", myname, rec_type); } } }
int post_mail_buffer(VSTREAM *cleanup, const char *buf, int len) { return (rec_put(cleanup, REC_TYPE_NORM, buf, len) != REC_TYPE_NORM ? CLEANUP_STAT_WRITE : 0); }
static int copy_segment(VSTREAM *qfile, VSTREAM *cleanup, PICKUP_INFO *info, VSTRING *buf, char *expected) { int type; int check_first = (*expected == REC_TYPE_CONTENT[0]); int time_seen = 0; char *attr_name; char *attr_value; char *saved_attr; int skip_attr; /* * Limit the input record size. All front-end programs should protect the * mail system against unreasonable inputs. This also requires that we * limit the size of envelope records written by the local posting agent. * * Records with named attributes are filtered by postdrop(1). * * We must allow PTR records here because of "postsuper -r". */ for (;;) { if ((type = rec_get(qfile, buf, var_line_limit)) < 0 || strchr(expected, type) == 0) return (file_read_error(info, type)); if (msg_verbose) msg_info("%s: read %c %s", info->id, type, vstring_str(buf)); if (type == *expected) break; if (type == REC_TYPE_FROM) { if (info->sender == 0) info->sender = mystrdup(vstring_str(buf)); /* Compatibility with Postfix < 2.3. */ if (time_seen == 0) rec_fprintf(cleanup, REC_TYPE_TIME, "%ld", (long) info->st.st_mtime); } if (type == REC_TYPE_TIME) time_seen = 1; /* * XXX Workaround: REC_TYPE_FILT (used in envelopes) == REC_TYPE_CONT * (used in message content). * * As documented in postsuper(1), ignore content filter record. */ if (*expected != REC_TYPE_CONTENT[0]) { if (type == REC_TYPE_FILT) /* Discard FILTER record after "postsuper -r". */ continue; if (type == REC_TYPE_RDR) /* Discard REDIRECT record after "postsuper -r". */ continue; } if (*expected == REC_TYPE_EXTRACT[0]) { if (type == REC_TYPE_RRTO) /* Discard return-receipt record after "postsuper -r". */ continue; if (type == REC_TYPE_ERTO) /* Discard errors-to record after "postsuper -r". */ continue; if (type == REC_TYPE_ATTR) { saved_attr = mystrdup(vstring_str(buf)); skip_attr = (split_nameval(saved_attr, &attr_name, &attr_value) == 0 && rec_attr_map(attr_name) == 0); myfree(saved_attr); /* Discard other/header/body action after "postsuper -r". */ if (skip_attr) continue; } } /* * XXX Force an empty record when the queue file content begins with * whitespace, so that it won't be considered as being part of our * own Received: header. What an ugly Kluge. */ if (check_first && (type == REC_TYPE_NORM || type == REC_TYPE_CONT)) { check_first = 0; if (VSTRING_LEN(buf) > 0 && IS_SPACE_TAB(vstring_str(buf)[0])) rec_put(cleanup, REC_TYPE_NORM, "", 0); } if ((REC_PUT_BUF(cleanup, type, buf)) < 0) return (cleanup_service_error(info, CLEANUP_STAT_WRITE)); } return (0); }
int main() { UCACHE *ushm; COUNTER counter; int num; char *fname, date[20]; FILE *fp; time_t now; struct tm *ptime; chdir(BBSHOME); if (!(fp = fopen(OUTFILE_COUNTER, "a+"))) return -1; fname = FN_RUN_COUNTER; memset(&counter, 0, sizeof(COUNTER)); rec_get(fname, &counter, sizeof(COUNTER), 0); counter.uptime = time(&now); ptime = localtime(&now); sprintf(date, "【%02d/%02d/%02d %02d:%02d】", ptime->tm_year % 100, ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min); /* 註冊人數 */ num = rec_num(FN_SCHEMA, sizeof(SCHEMA)); if (break_record(num, counter.total_acct)) { fprintf(fp, "★ %s \033[31m本站註冊人數\033[m狂賀超過 \033[1;31m%d\033[m 人\n", date, num); counter.total_acct = num; } /* 線上人數 */ ushm = shm_new(UTMPSHM_KEY, sizeof(UCACHE)); num = ushm->count; if (break_record(num, counter.online_usr)) { fprintf(fp, "◎ %s \033[32m同時線上人數\033[m首次達到 \033[1;32m%d\033[m 人\n", date, num); counter.online_usr = num; } counter.online_usr_every_hour[ptime->tm_hour] = num; /* 本小時的線上人數,就拿這次 sample 值 */ /* 本日上站人次 */ if (ptime->tm_hour == 23) /* 每天計算一次本日上站人次 */ { int i; /* itoc.註解: 這個值是不正確的,因為只是拿每個小時 sample 的和, 而且還假設每個人平均在站上時間是 60 分鐘 */ num = 0; for (i = 0; i < 24; i++) num += counter.online_usr_every_hour[i]; if (break_record(num, counter.today_usr)) { fprintf(fp, "◆ %s \033[33m單日上站人次\033[m正式突破 \033[1;33m%d\033[m 人\n", date, num); counter.today_usr = num; } } /* 看板個數 */ num = rec_num(FN_BRD, sizeof(BRD)); if (break_record(num, counter.total_brd)) { fprintf(fp, "☆ %s \033[34m本站看板個數\033[m宣佈高達 \033[1;34m%d\033[m 個\n", date, num); counter.total_brd = num; } rec_put(fname, &counter, sizeof(COUNTER), 0, NULL); fclose(fp); return 0; }
static int smtpd_proxy_replay_send(SMTPD_STATE *state) { const char *myname = "smtpd_proxy_replay_send"; static VSTRING *replay_buf = 0; SMTPD_PROXY *proxy = state->proxy; int rec_type; int expect = SMTPD_PROX_WANT_BAD; /* * Sanity check. */ if (smtpd_proxy_replay_stream == 0) msg_panic("%s: no before-queue filter speed-adjust log", myname); /* * Errors first. */ if (vstream_ferror(smtpd_proxy_replay_stream) || vstream_feof(smtpd_proxy_replay_stream) || rec_put(smtpd_proxy_replay_stream, REC_TYPE_END, "", 0) != REC_TYPE_END || vstream_fflush(smtpd_proxy_replay_stream)) /* NOT: fsync(vstream_fileno(smtpd_proxy_replay_stream)) */ return (smtpd_proxy_replay_rdwr_error(state)); /* * Delayed connection to the before-queue filter. */ if (smtpd_proxy_connect(state) < 0) return (-1); /* * Replay the speed-match log. We do sanity check record content, but we * don't implement a protocol state engine here, since we are reading * from a file that we just wrote ourselves. */ if (replay_buf == 0) replay_buf = vstring_alloc(100); if (vstream_fseek(smtpd_proxy_replay_stream, (off_t) 0, SEEK_SET) < 0) return (smtpd_proxy_replay_rdwr_error(state)); for (;;) { switch (rec_type = rec_get(smtpd_proxy_replay_stream, replay_buf, REC_FLAG_NONE)) { /* * Message content. */ case REC_TYPE_NORM: case REC_TYPE_CONT: if (smtpd_proxy_rec_put(proxy->service_stream, rec_type, STR(replay_buf), LEN(replay_buf)) < 0) return (-1); break; /* * Expected server reply type. */ case REC_TYPE_RCPT: if (!alldig(STR(replay_buf)) || (expect = atoi(STR(replay_buf))) == SMTPD_PROX_WANT_BAD) msg_panic("%s: malformed server reply type: %s", myname, STR(replay_buf)); break; /* * Client command, or void. Bail out on the first negative proxy * response. This is OK, because the filter must use the same * reply code for all recipients of a multi-recipient message. */ case REC_TYPE_FROM: if (expect == SMTPD_PROX_WANT_BAD) msg_panic("%s: missing server reply type", myname); if (smtpd_proxy_cmd(state, expect, *STR(replay_buf) ? "%s" : SMTPD_PROXY_CONN_FMT, STR(replay_buf)) < 0) return (-1); expect = SMTPD_PROX_WANT_BAD; break; /* * Explicit end marker, instead of implicit EOF. */ case REC_TYPE_END: return (0); /* * Errors. */ case REC_TYPE_ERROR: return (smtpd_proxy_replay_rdwr_error(state)); default: msg_panic("%s: unexpected record type; %d", myname, rec_type); } } }