bool DemanderQuiEstClient(string & nom, int & nbre, FileAttente & laFile) { if (laFile.EstVide()) throw exception("\n La file est vide \n"); bool recommencer = false; char choix; do // demander tant qu'il n'a pas entrer des données qui existe { cout << " Quel était le nom de votre réservation ? "; cin >> nom; cout << " Pour combien de personnes avez vous réservé ? "; cin >> nbre; if (!laFile.VérifierSiPrésent(nom, nbre)) // utilise la fonction verifier si présent pour analyser données entrées par le user { cout << " Vous n'avez pas donné les bonnes informations, recommencez ? (o/n) "; do { cin >> choix; } while (choix != 'o' && choix != 'n'); if (choix == 'n') { recommencer = true; } } } while (!laFile.VérifierSiPrésent(nom, nbre) && !recommencer); return recommencer; }
static int deliver_message(DELIVER_REQUEST *request) { const char *myname = "deliver_message"; VSTREAM *src; int result = 0; int status; RECIPIENT *rcpt; int nrcpt; DSN_SPLIT dp; DSN dsn; if (msg_verbose) msg_info("deliver_message: from %s", request->sender); /* * Sanity checks. */ if (request->nexthop[0] == 0) msg_fatal("empty nexthop hostname"); if (request->rcpt_list.len <= 0) msg_fatal("recipient count: %d", request->rcpt_list.len); /* * Open the queue file. Opening the file can fail for a variety of * reasons, such as the system running out of resources. Instead of * throwing away mail, we're raising a fatal error which forces the mail * system to back off, and retry later. */ src = mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0); if (src == 0) msg_fatal("%s: open %s %s: %m", myname, request->queue_name, request->queue_id); if (msg_verbose) msg_info("%s: file %s", myname, VSTREAM_PATH(src)); /* * Discard all recipients. */ #define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS(request->flags) dsn_split(&dp, "2.0.0", request->nexthop); (void) DSN_SIMPLE(&dsn, DSN_STATUS(dp.dsn), dp.text); for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) { rcpt = request->rcpt_list.info + nrcpt; status = sent(BOUNCE_FLAGS(request), request->queue_id, &request->msg_stats, rcpt, "none", &dsn); if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(src, rcpt->offset); result |= status; } /* * Clean up. */ if (vstream_fclose(src)) msg_warn("close %s %s: %m", request->queue_name, request->queue_id); return (result); }
bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) { if (RR->node->putPacket(_localAddress,address(),data,len)) { sent(now); return true; } return false; }
void InputDialog::sentData() { close(); emit sent( getName(), getNumber() ); }
void TcpSocket::write(QByteArray data) { if(socketConnected) { socket->write(data); Q_EMIT sent(data); } else qDebug()<<this->objectName() + " not connected!"; }
static int eval_command_status(int command_status, char *service, DELIVER_REQUEST *request, PIPE_ATTR *attr, DSN_BUF *why) { RECIPIENT *rcpt; int status; int result = 0; int n; /* * Depending on the result, bounce or defer the message, and mark the * recipient as done where appropriate. */ switch (command_status) { case PIPE_STAT_OK: dsb_update(why, "2.0.0", (attr->flags & PIPE_OPT_FINAL_DELIVERY) ? "delivered" : "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY, "delivered via %s service", service); (void) DSN_FROM_DSN_BUF(why); for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, service, &why->dsn); if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(request->fp, rcpt->offset); result |= status; } break; case PIPE_STAT_BOUNCE: case PIPE_STAT_DEFER: (void) DSN_FROM_DSN_BUF(why); for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; /* XXX Maybe encapsulate this with ndr_append(). */ status = (STR(why->status)[0] != '4' ? bounce_append : defer_append) (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, service, &why->dsn); if (status == 0) deliver_completed(request->fp, rcpt->offset); result |= status; } break; case PIPE_STAT_CORRUPT: /* XXX DSN should we send something? */ result |= DEL_STAT_DEFER; break; default: msg_panic("eval_command_status: bad status %d", command_status); /* NOTREACHED */ } return (result); }
static err_t connected(void *arg, struct tcp_pcb *tpcb, err_t err) { struct iperf_state *is = (struct iperf_state *) arg; print_connection_msg("tx", tpcb); tcp_sent(tpcb, sent); sent(is, tpcb, 0); return ERR_OK; }
BOOST_FIXTURE_TEST_CASE(test_muchos_coros, fixture) { const int NUM = 1000; const int MSGS = 10000; std::atomic<int> received(0); std::atomic<int> sent(0); std::atomic<int> coros(0); for(int i = 0; i < NUM; i++) { channel_pair<int> pair = make_channel<int>(10); go(std::string("test_muchos_coros reader"), [&received, &coros](channel_reader<int>& r) { coros++; for(int i = 0; i < MSGS; i++) { try { r.get(); received++; } catch(const channel_closed&) { std::cout << "channel closed after readig only " << i << " msgs" << std::endl; throw; } } }, std::move(pair.reader)); go(std::string("test_muchos_coros writer"), [&sent, &coros](channel_writer<int>& w) { coros++; for(int i = 0; i < MSGS; i++) { try { w.put(i); sent++; } catch(const channel_closed&) { std::cout << "channel closed after writing only " << i << " msgs" << std::endl; throw; } } }, std::move(pair.writer)); } wait_for_completion(); BOOST_CHECK_EQUAL(coros, NUM*2); BOOST_CHECK_EQUAL(received, NUM*MSGS); BOOST_CHECK_EQUAL(sent, NUM*MSGS); }
void CleanAsyncRequest::sltTimerTimeout() { stanza()->addAttribute("type", "groupchat"); stanza()->finalize(); plugin()->reply(stanza(), "", false, false); count_ --; sent_ ++; if( count() <= 0 ) { timer_->stop(); plugin()->reply(stanza(), QString("Clean finished: %1 messages sent.").arg(sent()), true); deleteLater(); } }
void InfoSender::send(Info info) { if(_logStream) { *_logStream << QTime::currentTime().toString().toAscii().data(); *_logStream << "\t"; *_logStream << info.infoMsg; *_logStream << "\n"; } if(info.infoType==ListInfo::INFODEBUG) qDebug(info.infoMsg.toLatin1().data()); emit sent(info); }
void SmtpClient::newConnection() { qMailLog(SMTP) << "newConnection" << flush; if (sending) { operationFailed(QMailServiceAction::Status::ErrConnectionInUse, tr("Cannot send message; transport in use")); return; } if (!config.id().isValid()) { status = Done; operationFailed(QMailServiceAction::Status::ErrConfiguration, tr("Cannot send message without account configuration")); return; } SmtpConfiguration smtpCfg(config); if ( smtpCfg.smtpServer().isEmpty() ) { status = Done; operationFailed(QMailServiceAction::Status::ErrConfiguration, tr("Cannot send message without SMTP server configuration")); return; } // Calculate the total indicative size of the messages we're sending totalSendSize = 0; foreach (uint size, sendSize.values()) totalSendSize += size; progressSendSize = 0; emit progressChanged(progressSendSize, totalSendSize); status = Init; sending = true; domainName = QByteArray(); outstandingResponses = 0; if (!transport) { // Set up the transport transport = new QMailTransport("SMTP"); connect(transport, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(transport, SIGNAL(connected(QMailTransport::EncryptType)), this, SLOT(connected(QMailTransport::EncryptType))); connect(transport, SIGNAL(bytesWritten(qint64)), this, SLOT(sent(qint64))); connect(transport, SIGNAL(updateStatus(QString)), this, SIGNAL(updateStatus(QString))); connect(transport, SIGNAL(errorOccurred(int,QString)), this, SLOT(transportError(int,QString))); }
void Sendmail::handleFinished(const int exitCode) { // that's the last one emit progressMax(dataToSend.size() + 2); if (exitCode == 0) { emit sent(); return; } QByteArray allStdout = proc->readAllStandardOutput(); QByteArray allStderr = proc->readAllStandardError(); emit error(tr("The sendmail process has failed (%1):\n%2\n%3").arg(QString::number(exitCode), QString::fromUtf8(allStdout), QString::fromUtf8(allStderr))); }
void SMTP::handleDone(bool ok) { if (failed) { // This is a duplicate notification. The QwwSmtpClient is known to send contradicting results, see e.g. bug 321272. return; } if (ok) { emit sent(); } else { failed = true; if (qwwSmtp->errorString().isEmpty()) emit error(tr("Sending of the message failed.")); else emit error(tr("Sending of the message failed with the following error: %1").arg(qwwSmtp->errorString())); } }
void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; SMTP_ITERATOR *iter = state->iterator; DSN_BUF *why = state->why; const char *dsn_action = "relayed"; int status; /* * Assume this was intermediate delivery when the server announced DSN * support, and don't send a DSN "SUCCESS" notification. */ if (session->features & SMTP_FEATURE_DSN) rcpt->dsn_notify &= ~DSN_NOTIFY_SUCCESS; /* * Assume this was final delivery when the LMTP server announced no DSN * support. In backwards compatibility mode, send a "relayed" instead of * a "delivered" DSN "SUCCESS" notification. Do not attempt to "simplify" * the expression. The redundancy is for clarity. It is trivially * eliminated by the compiler. There is no need to sacrifice clarity for * the sake of "performance". */ if ((session->features & SMTP_FEATURE_DSN) == 0 && !smtp_mode && var_lmtp_assume_final != 0) dsn_action = "delivered"; /* * Report success and delete the recipient from the delivery request. * Defer if the success can't be reported. * * Note: the DSN action is ignored in case of address probes. */ dsb_update(why, resp->dsn, dsn_action, DSB_MTYPE_DNS, STR(iter->host), DSB_DTYPE_SMTP, resp->str, "%s", resp->str); status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, session->namaddrport, DSN_FROM_DSN_BUF(why)); if (status == 0) if (request->flags & DEL_REQ_FLAG_SUCCESS) deliver_completed(state->src, rcpt->offset); SMTP_RCPT_DROP(state, rcpt); state->status |= status; }
/** * @details * Send data to connected clients */ void TCPConnectionManager::send(const QString& streamName, const DataBlob* blob) { QMutexLocker sendlocker(&_sendMutex); // Check if there are any client reading streamName type data if (_clients.contains(streamName) ) { clients_t clientListCopy; { // control access to the _clients QMutexLocker locker(&_mutex); clientListCopy = _clients[streamName]; } for(int i = 0; i < clientListCopy.size(); ++i ) { QTcpSocket* client = clientListCopy[i]; // Send data to client try { //std::cout << "Sending blob of type " << blob->type().toStdString() // << " on stream " << streamName.toStdString() << " to:" // << client->peerName().toStdString() << std::endl; Q_ASSERT( client->state() == QAbstractSocket::ConnectedState ); _protocol->send(*client, streamName, *blob); client->flush(); } catch ( ... ) { // kill the client if anything goes wrong std::cerr << "TCPConnectionManager: failed to send data to client" << std::endl; _killClient(client); } } } emit sent(blob); // let any blocked sends continue // now the blob is sent. // Ensure we track the data streams and inform any interested // clients of updates. if( !_seenTypes.contains(streamName) ) { _seenTypes.insert(streamName); _sendNewDataTypes(); } }
void FileTransfer::slotExec() { char buf[2]; if (::read(m_term[0], buf, 1 ) == -1) owarn << "read of m_term[0] failed" << oendl; delete m_proc; delete m_not; m_proc = m_not = 0l; close( m_term[0] ); close( m_term[1] ); close( m_comm[0] ); close( m_comm[1] ); if (m_fd >= 0) layer()->closeRawIO( m_fd ); emit sent(); m_pid = 0; }
QString KDBSearchEngine2::searchTranslation( const QString text, int & score ) { GenericSearchAlgorithm strategy(di,&settings); strategy.setMaxResultNumber(1); ExactSearchAlgorithm exact(di,&settings); AlphaSearchAlgorithm alpha(di,&settings); SentenceArchiveSearchAlgorithm sent(di,&settings); strategy.addAlgorithm(&exact); strategy.addAlgorithm(&alpha); strategy.addAlgorithm(&sent); QueryResult firstRes=strategy.exec(text)[0]; score=firstRes.score(); return firstRes.result(); }
QString KDBSearchEngine2::fuzzyTranslation( const QString text, int & score ) { GenericSearchAlgorithm strategy(di,&settings); strategy.setMaxResultNumber(1); ExactSearchAlgorithm exact(di,&settings); AlphaSearchAlgorithm alpha(di,&settings); SentenceArchiveSearchAlgorithm sent(di,&settings); ChunkByChunkSearchAlgorithm sbys(di,&settings); ChunkByChunkSearchAlgorithm wbyw(di,&settings); FuzzyChunkSearchAlgorithm fs(di,&settings); FuzzyChunkSearchAlgorithm fw(di,&settings); SentenceChunkFactory sf(di); sbys.setChunkFactory(&sf); fs.setChunkFactory(&sf); WordChunkFactory wf(di); wbyw.setChunkFactory(&wf); fw.setChunkFactory(&wf); strategy.addAlgorithm(&exact); strategy.addAlgorithm(&alpha); strategy.addAlgorithm(&sent); strategy.addAlgorithm(&sbys); //strategy.addAlgorithm(&fs); strategy.addAlgorithm(&fw); strategy.addAlgorithm(&wbyw); QueryResult firstRes=strategy.exec(text)[0]; score=firstRes.score(); return firstRes.result(); }
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); }
static int eval_command_status(int command_status, char *service, DELIVER_REQUEST *request, PIPE_ATTR *attr, DSN_BUF *why) { RECIPIENT *rcpt; int status; int result = 0; int n; char *saved_text; /* * Depending on the result, bounce or defer the message, and mark the * recipient as done where appropriate. */ switch (command_status) { case PIPE_STAT_OK: /* Save the command output before dsb_update() clobbers it. */ vstring_truncate(why->reason, trimblanks(STR(why->reason), VSTRING_LEN(why->reason)) - STR(why->reason)); if (VSTRING_LEN(why->reason) > 0) { VSTRING_TERMINATE(why->reason); saved_text = vstring_export(vstring_sprintf( vstring_alloc(VSTRING_LEN(why->reason)), " (%.100s)", STR(why->reason))); } else saved_text = mystrdup(""); /* uses shared R/O storage */ dsb_update(why, "2.0.0", (attr->flags & PIPE_OPT_FINAL_DELIVERY) ? "delivered" : "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY, "delivered via %s service%s", service, saved_text); myfree(saved_text); (void) DSN_FROM_DSN_BUF(why); for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, service, &why->dsn); if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(request->fp, rcpt->offset); result |= status; } break; case PIPE_STAT_BOUNCE: case PIPE_STAT_DEFER: (void) DSN_FROM_DSN_BUF(why); for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; /* XXX Maybe encapsulate this with ndr_append(). */ status = (STR(why->status)[0] != '4' ? bounce_append : defer_append) (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, service, &why->dsn); if (status == 0) deliver_completed(request->fp, rcpt->offset); result |= status; } break; case PIPE_STAT_CORRUPT: /* XXX DSN should we send something? */ result |= DEL_STAT_DEFER; break; default: msg_panic("eval_command_status: bad status %d", command_status); /* NOTREACHED */ } return (result); }
void SerialPortManager::send(const QByteArray data) { if(m_serialPort->isOpen()){ emit sent(m_serialPort->write(data)); } }
static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv) { const char *myname = "deliver_message"; static PIPE_PARAMS conf; static PIPE_ATTR attr; RECIPIENT_LIST *rcpt_list = &request->rcpt_list; DSN_BUF *why = dsb_create(); VSTRING *buf; ARGV *expanded_argv = 0; int deliver_status; int command_status; ARGV *export_env; const char *sender; #define DELIVER_MSG_CLEANUP() { \ dsb_free(why); \ if (expanded_argv) argv_free(expanded_argv); \ } if (msg_verbose) msg_info("%s: from <%s>", myname, request->sender); /* * Sanity checks. The get_service_params() and get_service_attr() * routines also do some sanity checks. Look up service attributes and * config information only once. This is safe since the information comes * from a trusted source, not from the delivery request. */ if (request->nexthop[0] == 0) msg_fatal("empty nexthop hostname"); if (rcpt_list->len <= 0) msg_fatal("recipient count: %d", rcpt_list->len); if (attr.command == 0) { get_service_params(&conf, service); get_service_attr(&attr, argv); } /* * The D flag cannot be specified for multi-recipient deliveries. */ if ((attr.flags & MAIL_COPY_DELIVERED) && (rcpt_list->len > 1)) { dsb_simple(why, "4.3.5", "mail system configuration error"); deliver_status = eval_command_status(PIPE_STAT_DEFER, service, request, &attr, why); msg_warn("pipe flag `D' requires %s_destination_recipient_limit = 1", service); DELIVER_MSG_CLEANUP(); return (deliver_status); } /* * The O flag cannot be specified for multi-recipient deliveries. */ if ((attr.flags & MAIL_COPY_ORIG_RCPT) && (rcpt_list->len > 1)) { dsb_simple(why, "4.3.5", "mail system configuration error"); deliver_status = eval_command_status(PIPE_STAT_DEFER, service, request, &attr, why); msg_warn("pipe flag `O' requires %s_destination_recipient_limit = 1", service); DELIVER_MSG_CLEANUP(); return (deliver_status); } /* * Check that this agent accepts messages this large. */ if (attr.size_limit != 0 && request->data_size > attr.size_limit) { if (msg_verbose) msg_info("%s: too big: size_limit = %ld, request->data_size = %ld", myname, (long) attr.size_limit, request->data_size); dsb_simple(why, "5.2.3", "message too large"); deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service, request, &attr, why); DELIVER_MSG_CLEANUP(); return (deliver_status); } /* * Don't deliver a trace-only request. */ if (DEL_REQ_TRACE_ONLY(request->flags)) { RECIPIENT *rcpt; int status; int n; deliver_status = 0; dsb_simple(why, "2.0.0", "delivers to command: %s", attr.command[0]); (void) DSN_FROM_DSN_BUF(why); for (n = 0; n < request->rcpt_list.len; n++) { rcpt = request->rcpt_list.info + n; status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, service, &why->dsn); if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(request->fp, rcpt->offset); deliver_status |= status; } DELIVER_MSG_CLEANUP(); return (deliver_status); } /* * Report mail delivery loops. By definition, this requires * single-recipient delivery. Don't silently lose recipients. */ if (attr.flags & MAIL_COPY_DELIVERED) { DELIVERED_HDR_INFO *info; RECIPIENT *rcpt; int loop_found; if (request->rcpt_list.len > 1) msg_panic("%s: delivered-to enabled with multi-recipient request", myname); info = delivered_hdr_init(request->fp, request->data_offset, FOLD_ADDR_ALL); rcpt = request->rcpt_list.info; loop_found = delivered_hdr_find(info, rcpt->address); delivered_hdr_free(info); if (loop_found) { dsb_simple(why, "5.4.6", "mail forwarding loop for %s", rcpt->address); deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service, request, &attr, why); DELIVER_MSG_CLEANUP(); return (deliver_status); } } /* * Deliver. Set the nexthop and sender variables, and expand the command * argument vector. Recipients will be expanded on the fly. XXX Rewrite * envelope and header addresses according to transport-specific * rewriting rules. */ if (vstream_fseek(request->fp, request->data_offset, SEEK_SET) < 0) msg_fatal("seek queue file %s: %m", VSTREAM_PATH(request->fp)); /* * A non-empty null sender replacement is subject to the 'q' flag. */ buf = vstring_alloc(10); sender = *request->sender ? request->sender : STR(attr.null_sender); if (*sender && (attr.flags & PIPE_OPT_QUOTE_LOCAL)) { quote_822_local(buf, sender); dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, STR(buf)); } else dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, sender); if (attr.flags & PIPE_OPT_FOLD_HOST) { vstring_strcpy(buf, request->nexthop); lowercase(STR(buf)); dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, STR(buf)); } else dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop); vstring_sprintf(buf, "%ld", (long) request->data_size); dict_update(PIPE_DICT_TABLE, PIPE_DICT_SIZE, STR(buf)); dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_ADDR, request->client_addr); dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_HELO, request->client_helo); dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_NAME, request->client_name); dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PORT, request->client_port); dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PROTO, request->client_proto); dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_METHOD, request->sasl_method); dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_USERNAME, request->sasl_username); dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_SENDER, request->sasl_sender); dict_update(PIPE_DICT_TABLE, PIPE_DICT_QUEUE_ID, request->queue_id); vstring_free(buf); if ((expanded_argv = expand_argv(service, attr.command, rcpt_list, attr.flags)) == 0) { dsb_simple(why, "4.3.5", "mail system configuration error"); deliver_status = eval_command_status(PIPE_STAT_DEFER, service, request, &attr, why); DELIVER_MSG_CLEANUP(); return (deliver_status); } export_env = argv_split(var_export_environ, ", \t\r\n"); command_status = pipe_command(request->fp, why, PIPE_CMD_UID, attr.uid, PIPE_CMD_GID, attr.gid, PIPE_CMD_SENDER, sender, PIPE_CMD_COPY_FLAGS, attr.flags, PIPE_CMD_ARGV, expanded_argv->argv, PIPE_CMD_TIME_LIMIT, conf.time_limit, PIPE_CMD_EOL, STR(attr.eol), PIPE_CMD_EXPORT, export_env->argv, PIPE_CMD_CWD, attr.exec_dir, PIPE_CMD_CHROOT, attr.chroot_dir, PIPE_CMD_ORIG_RCPT, rcpt_list->info[0].orig_addr, PIPE_CMD_DELIVERED, rcpt_list->info[0].address, PIPE_CMD_END); argv_free(export_env); deliver_status = eval_command_status(command_status, service, request, &attr, why); /* * Clean up. */ DELIVER_MSG_CLEANUP(); return (deliver_status); }
int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path) { const char *myname = "deliver_file"; struct stat st; MBOX *mp; DSN_BUF *why = state.msg_attr.why; int mail_copy_status = MAIL_COPY_STAT_WRITE; int deliver_status; int copy_flags; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * DUPLICATE ELIMINATION * * Skip this file if it was already delivered to as this user. */ if (been_here(state.dup_filter, "file %ld %s", (long) usr_attr.uid, path)) return (0); /* * DELIVERY POLICY * * Do we allow delivery to files? */ if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0) { dsb_simple(why, "5.7.1", "mail to file is restricted"); /* Account for possible owner- sender address override. */ return (bounce_workaround(state)); } /* * Don't deliver trace-only requests. */ if (DEL_REQ_TRACE_ONLY(state.request->flags)) { dsb_simple(why, "2.0.0", "delivers to file: %s", path); return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr))); } /* * DELIVERY RIGHTS * * Use a default uid/gid when none are given. */ if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0) msg_panic("privileged default user id"); if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0) msg_panic("privileged default group id"); /* * If the name ends in /, use maildir-style delivery instead. */ if (path[strlen(path) - 1] == '/') return (deliver_maildir(state, usr_attr, path)); /* * Deliver. From here on, no early returns or we have a memory leak. */ if (msg_verbose) msg_info("deliver_file (%ld,%ld): %s", (long) usr_attr.uid, (long) usr_attr.gid, path); if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("seek queue file %s: %m", state.msg_attr.queue_id); /* * As the specified user, open or create the file, lock it, and append * the message. */ copy_flags = MAIL_COPY_MBOX; if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0) copy_flags &= ~MAIL_COPY_DELIVERED; set_eugid(usr_attr.uid, usr_attr.gid); mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR, &st, -1, -1, local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL, "5.2.0", why); if (mp != 0) { if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { vstream_fclose(mp->fp); dsb_simple(why, "5.7.1", "file is executable"); } else { mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, S_ISREG(st.st_mode) ? copy_flags : (copy_flags & ~MAIL_COPY_TOFILE), "\n", why); } mbox_release(mp); } set_eugid(var_owner_uid, var_owner_gid); /* * As the mail system, bounce, defer delivery, or report success. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { vstring_sprintf_prepend(why->reason, "cannot append message to file %s: ", path); if (STR(why->status)[0] == '4') deliver_status = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); else /* Account for possible owner- sender address override. */ deliver_status = bounce_workaround(state); } else { dsb_simple(why, "2.0.0", "delivered to file: %s", path); deliver_status = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)); } return (deliver_status); }
void SmtpClient::newConnection() { qMailLog(SMTP) << "newConnection" << flush; #ifdef USE_ACCOUNTS_QT loginFailed = false; #endif if (sending) { operationFailed(QMailServiceAction::Status::ErrConnectionInUse, tr("Cannot send message; transport in use")); return; } if (!config.id().isValid()) { status = Done; operationFailed(QMailServiceAction::Status::ErrConfiguration, tr("Cannot send message without account configuration")); return; } // Load the current configuration for this account // Reload the account configuration whenever a new SMTP // connection is created, in order to ensure the changes // in the account settings are being managed properly. config = QMailAccountConfiguration(config.id()); SmtpConfiguration smtpCfg(config); if ( smtpCfg.smtpServer().isEmpty() ) { status = Done; operationFailed(QMailServiceAction::Status::ErrConfiguration, tr("Cannot send message without SMTP server configuration")); return; } // Calculate the total indicative size of the messages we're sending totalSendSize = 0; foreach (uint size, sendSize.values()) totalSendSize += size; progressSendSize = 0; emit progressChanged(progressSendSize, totalSendSize); status = Init; sending = true; domainName = QByteArray(); outstandingResponses = 0; if (!transport) { // Set up the transport transport = new QMailTransport("SMTP"); connect(transport, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(transport, SIGNAL(connected(QMailTransport::EncryptType)), this, SLOT(connected(QMailTransport::EncryptType))); connect(transport, SIGNAL(bytesWritten(qint64)), this, SLOT(sent(qint64))); connect(transport, SIGNAL(updateStatus(QString)), this, SIGNAL(updateStatus(QString))); connect(transport, SIGNAL(errorOccurred(int,QString)), this, SLOT(transportError(int,QString))); #ifndef QT_NO_OPENSSL connect(transport, SIGNAL(sslErrorOccured(QMailServiceAction::Status::ErrorCode,QString)), this, SIGNAL(connectionError(QMailServiceAction::Status::ErrorCode,QString))); #endif }
int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *command) { const char *myname = "deliver_command"; DSN_BUF *why = state.msg_attr.why; int cmd_status; int deliver_status; ARGV *env; int copy_flags; char **cpp; char *cp; ARGV *export_env; VSTRING *exec_dir; int expand_status; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * DUPLICATE ELIMINATION * * Skip this command if it was already delivered to as this user. */ if (been_here(state.dup_filter, "command %s:%ld %s", state.msg_attr.user, (long) usr_attr.uid, command)) return (0); /* * Don't deliver a trace-only request. */ if (DEL_REQ_TRACE_ONLY(state.request->flags)) { dsb_simple(why, "2.0.0", "delivers to command: %s", command); return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr))); } /* * DELIVERY RIGHTS * * Choose a default uid and gid when none have been selected (i.e. values * are still zero). */ if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0) msg_panic("privileged default user id"); if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0) msg_panic("privileged default group id"); /* * Deliver. */ copy_flags = MAIL_COPY_FROM | MAIL_COPY_RETURN_PATH | MAIL_COPY_ORIG_RCPT; if (local_deliver_hdr_mask & DELIVER_HDR_CMD) copy_flags |= MAIL_COPY_DELIVERED; if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("%s: seek queue file %s: %m", myname, VSTREAM_PATH(state.msg_attr.fp)); /* * Pass additional environment information. XXX This should be * configurable. However, passing untrusted information via environment * parameters opens up a whole can of worms. Lesson from web servers: * don't let any network data even near a shell. It causes trouble. */ env = argv_alloc(1); if (usr_attr.home) argv_add(env, "HOME", usr_attr.home, ARGV_END); argv_add(env, "LOGNAME", state.msg_attr.user, "USER", state.msg_attr.user, "SENDER", state.msg_attr.sender, "RECIPIENT", state.msg_attr.rcpt.address, "LOCAL", state.msg_attr.local, ARGV_END); if (usr_attr.shell) argv_add(env, "SHELL", usr_attr.shell, ARGV_END); if (state.msg_attr.domain) argv_add(env, "DOMAIN", state.msg_attr.domain, ARGV_END); if (state.msg_attr.extension) argv_add(env, "EXTENSION", state.msg_attr.extension, ARGV_END); if (state.msg_attr.rcpt.orig_addr && state.msg_attr.rcpt.orig_addr[0]) argv_add(env, "ORIGINAL_RECIPIENT", state.msg_attr.rcpt.orig_addr, ARGV_END); #define EXPORT_REQUEST(name, value) \ if ((value)[0]) argv_add(env, (name), (value), ARGV_END); EXPORT_REQUEST("CLIENT_HOSTNAME", state.msg_attr.request->client_name); EXPORT_REQUEST("CLIENT_ADDRESS", state.msg_attr.request->client_addr); EXPORT_REQUEST("CLIENT_HELO", state.msg_attr.request->client_helo); EXPORT_REQUEST("CLIENT_PROTOCOL", state.msg_attr.request->client_proto); EXPORT_REQUEST("SASL_METHOD", state.msg_attr.request->sasl_method); EXPORT_REQUEST("SASL_SENDER", state.msg_attr.request->sasl_sender); EXPORT_REQUEST("SASL_USERNAME", state.msg_attr.request->sasl_username); argv_terminate(env); /* * Censor out undesirable characters from exported data. */ for (cpp = env->argv; *cpp; cpp += 2) for (cp = cpp[1]; *(cp += strspn(cp, var_cmd_exp_filter)) != 0;) *cp++ = '_'; /* * Evaluate the command execution directory. Defer delivery if expansion * fails. */ export_env = mail_parm_split(VAR_EXPORT_ENVIRON, var_export_environ); exec_dir = vstring_alloc(10); expand_status = local_expand(exec_dir, var_exec_directory, &state, &usr_attr, var_exec_exp_filter); if (expand_status & MAC_PARSE_ERROR) { cmd_status = PIPE_STAT_DEFER; dsb_simple(why, "4.3.5", "mail system configuration error"); msg_warn("bad parameter value syntax for %s: %s", VAR_EXEC_DIRECTORY, var_exec_directory); } else { cmd_status = pipe_command(state.msg_attr.fp, why, PIPE_CMD_UID, usr_attr.uid, PIPE_CMD_GID, usr_attr.gid, PIPE_CMD_COMMAND, command, PIPE_CMD_COPY_FLAGS, copy_flags, PIPE_CMD_SENDER, state.msg_attr.sender, PIPE_CMD_ORIG_RCPT, state.msg_attr.rcpt.orig_addr, PIPE_CMD_DELIVERED, state.msg_attr.delivered, PIPE_CMD_TIME_LIMIT, var_command_maxtime, PIPE_CMD_ENV, env->argv, PIPE_CMD_EXPORT, export_env->argv, PIPE_CMD_SHELL, var_local_cmd_shell, PIPE_CMD_CWD, *STR(exec_dir) ? STR(exec_dir) : (char *) 0, PIPE_CMD_END); } vstring_free(exec_dir); argv_free(export_env); argv_free(env); /* * Depending on the result, bounce or defer the message. */ switch (cmd_status) { case PIPE_STAT_OK: dsb_simple(why, "2.0.0", "delivered to command: %s", command); deliver_status = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)); break; case PIPE_STAT_BOUNCE: case PIPE_STAT_DEFER: /* Account for possible owner- sender address override. */ deliver_status = bounce_workaround(state); break; case PIPE_STAT_CORRUPT: deliver_status = DEL_STAT_DEFER; break; default: msg_panic("%s: bad status %d", myname, cmd_status); /* NOTREACHED */ } return (deliver_status); }
int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr) { const char *myname = "deliver_unknown"; int status; VSTRING *expand_luser; static MAPS *transp_maps; const char *map_transport; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * DUPLICATE/LOOP ELIMINATION * * Don't deliver the same user twice. */ if (been_here(state.dup_filter, "%s %s", myname, state.msg_attr.local)) return (0); /* * The fall-back transport specifies a delivery machanism that handles * users not found in the aliases or UNIX passwd databases. */ if (*var_fbck_transp_maps && transp_maps == 0) transp_maps = maps_create(VAR_FBCK_TRANSP_MAPS, var_fbck_transp_maps, DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB); /* The -1 is a hint for the down-stream deliver_completed() function. */ if (transp_maps && (map_transport = maps_find(transp_maps, state.msg_attr.user, DICT_FLAG_NONE)) != 0) { state.msg_attr.rcpt.offset = -1L; return (deliver_pass(MAIL_CLASS_PRIVATE, map_transport, state.request, &state.msg_attr.rcpt)); } else if (transp_maps && transp_maps->error != 0) { /* Details in the logfile. */ dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure"); return (defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr))); } if (*var_fallback_transport) { state.msg_attr.rcpt.offset = -1L; return (deliver_pass(MAIL_CLASS_PRIVATE, var_fallback_transport, state.request, &state.msg_attr.rcpt)); } /* * Subject the luser_relay address to $name expansion, disable * propagation of unmatched address extension, and re-inject the address * into the delivery machinery. Do not give special treatment to "|stuff" * or /stuff. */ if (*var_luser_relay) { state.msg_attr.unmatched = 0; expand_luser = vstring_alloc(100); local_expand(expand_luser, var_luser_relay, &state, &usr_attr, (char *) 0); status = deliver_resolve_addr(state, usr_attr, STR(expand_luser)); vstring_free(expand_luser); return (status); } /* * If no alias was found for a required reserved name, toss the message * into the bit bucket, and issue a warning instead. */ #define STREQ(x,y) (strcasecmp(x,y) == 0) if (STREQ(state.msg_attr.local, MAIL_ADDR_MAIL_DAEMON) || STREQ(state.msg_attr.local, MAIL_ADDR_POSTMASTER)) { msg_warn("required alias not found: %s", state.msg_attr.local); dsb_simple(state.msg_attr.why, "2.0.0", "discarded"); return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr))); } /* * Bounce the message when no luser relay is specified. */ dsb_simple(state.msg_attr.why, "5.1.1", "unknown user: \"%s\"", state.msg_attr.local); return (bounce_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr))); }
static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) { const char *myname = "deliver_mailbox_file"; char *spool_dir; char *mailbox; DSN_BUF *why = state.msg_attr.why; MBOX *mp; int mail_copy_status; int deliver_status; int copy_flags; VSTRING *biff; long end; struct stat st; uid_t spool_uid; gid_t spool_gid; uid_t chown_uid; gid_t chown_gid; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * Don't deliver trace-only requests. */ if (DEL_REQ_TRACE_ONLY(state.request->flags)) { dsb_simple(why, "2.0.0", "delivers to mailbox"); return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr))); } /* * Initialize. Assume the operation will fail. Set the delivered * attribute to reflect the final recipient. */ if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); if (var_frozen_delivered == 0) state.msg_attr.delivered = state.msg_attr.rcpt.address; mail_copy_status = MAIL_COPY_STAT_WRITE; if (*var_home_mailbox) { spool_dir = 0; mailbox = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0); } else { spool_dir = var_mail_spool_dir; mailbox = concatenate(spool_dir, "/", state.msg_attr.user, (char *) 0); } /* * Mailbox delivery with least privilege. As long as we do not use root * privileges this code may also work over NFS. * * If delivering to the recipient's home directory, perform all operations * (including file locking) as that user (Mike Muuss, Army Research * Laboratory, USA). * * If delivering to the mail spool directory, and the spool directory is * world-writable, deliver as the recipient; if the spool directory is * group-writable, use the recipient user id and the mail spool group id. * * Otherwise, use root privileges and chown the mailbox. */ if (spool_dir == 0 || stat(spool_dir, &st) < 0 || (st.st_mode & S_IWOTH) != 0) { spool_uid = usr_attr.uid; spool_gid = usr_attr.gid; } else if ((st.st_mode & S_IWGRP) != 0) { spool_uid = usr_attr.uid; spool_gid = st.st_gid; } else { spool_uid = 0; spool_gid = 0; } if (spool_uid == usr_attr.uid) { chown_uid = -1; chown_gid = -1; } else { chown_uid = usr_attr.uid; chown_gid = usr_attr.gid; } if (msg_verbose) msg_info("spool_uid/gid %ld/%ld chown_uid/gid %ld/%ld", (long) spool_uid, (long) spool_gid, (long) chown_uid, (long) chown_gid); /* * Lock the mailbox and open/create the mailbox file. Depending on the * type of locking used, we lock first or we open first. * * Write the file as the recipient, so that file quota work. */ copy_flags = MAIL_COPY_MBOX; if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0) copy_flags &= ~MAIL_COPY_DELIVERED; set_eugid(spool_uid, spool_gid); mp = mbox_open(mailbox, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, &st, chown_uid, chown_gid, local_mbox_lock_mask, "5.2.0", why); if (mp != 0) { if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid) set_eugid(usr_attr.uid, usr_attr.gid); if (S_ISREG(st.st_mode) == 0) { vstream_fclose(mp->fp); dsb_simple(why, "5.2.0", "destination %s is not a regular file", mailbox); } else if (var_strict_mbox_owner && st.st_uid != usr_attr.uid) { vstream_fclose(mp->fp); dsb_simple(why, "4.2.0", "destination %s is not owned by recipient", mailbox); msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch", VAR_STRICT_MBOX_OWNER); } else { end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END); mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, copy_flags, "\n", why); } if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid) set_eugid(spool_uid, spool_gid); mbox_release(mp); } set_eugid(var_owner_uid, var_owner_gid); /* * As the mail system, bounce, defer delivery, or report success. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { vstring_sprintf_prepend(why->reason, "cannot update mailbox %s for user %s. ", mailbox, state.msg_attr.user); deliver_status = (STR(why->status)[0] == '4' ? defer_append : bounce_append) (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); } else { dsb_simple(why, "2.0.0", "delivered to mailbox"); deliver_status = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)); if (var_biff) { biff = vstring_alloc(100); vstring_sprintf(biff, "%s@%ld", usr_attr.logname, (long) end); biff_notify(STR(biff), VSTRING_LEN(biff) + 1); vstring_free(biff); } } /* * Clean up. */ myfree(mailbox); return (deliver_status); }
static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) { const char *myname = "deliver_mailbox_file"; DSN_BUF *why = state.msg_attr.why; MBOX *mp; int mail_copy_status; int deliver_status; int copy_flags; long end; struct stat st; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * Don't deliver trace-only requests. */ if (DEL_REQ_TRACE_ONLY(state.request->flags)) { dsb_simple(why, "2.0.0", "delivers to mailbox"); return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr))); } /* * Initialize. Assume the operation will fail. Set the delivered * attribute to reflect the final recipient. */ if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); state.msg_attr.delivered = state.msg_attr.rcpt.address; mail_copy_status = MAIL_COPY_STAT_WRITE; /* * Lock the mailbox and open/create the mailbox file. * * Write the file as the recipient, so that file quota work. */ copy_flags = MAIL_COPY_MBOX; set_eugid(usr_attr.uid, usr_attr.gid); mp = mbox_open(usr_attr.mailbox, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, &st, -1, -1, virtual_mbox_lock_mask, "4.2.0", why); if (mp != 0) { if (S_ISREG(st.st_mode) == 0) { vstream_fclose(mp->fp); msg_warn("recipient %s: destination %s is not a regular file", state.msg_attr.rcpt.address, usr_attr.mailbox); dsb_simple(why, "5.3.5", "mail system configuration error"); } else if (var_strict_mbox_owner && st.st_uid != usr_attr.uid) { vstream_fclose(mp->fp); dsb_simple(why, "4.2.0", "destination %s is not owned by recipient", usr_attr.mailbox); msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch", VAR_STRICT_MBOX_OWNER); } else { end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END); mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, copy_flags, "\n", why); } mbox_release(mp); } set_eugid(var_owner_uid, var_owner_gid); /* * As the mail system, bounce, defer delivery, or report success. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { vstring_sprintf_prepend(why->reason, "delivery failed to mailbox %s: ", usr_attr.mailbox); deliver_status = (STR(why->status)[0] == '4' ? defer_append : bounce_append) (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); } else { dsb_simple(why, "2.0.0", "delivered to mailbox"); deliver_status = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)); } return (deliver_status); }
int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, char *name, int *statusp) { char *myname = "deliver_alias"; const char *alias_result; char *expansion; 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; /* * 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("possible alias database loop for %s", name); *statusp = bounce_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr), "possible alias database loop for %s", name); 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_VERIFY) { *statusp = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr), "aliased to %s", alias_result); 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); *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr), "cannot find alias database owner"); 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 STR(x) vstring_str(x) #define OWNER_ASSIGN(own) \ (own = (var_ownreq_special == 0 ? 0 : \ concatenate("owner-", name, (char *) 0))) expansion = 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_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level); } else { canon_owner = 0; 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. */ state.msg_attr.delivered = state.msg_attr.recipient; /* * Deliver. */ alias_count = 0; *statusp = (dict_errno ? defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr), "alias database unavailable") : deliver_token_string(state, usr_attr, expansion, &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); *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr), "alias database unavailable"); } myfree(expansion); 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) { *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr), "alias database unavailable"); 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); }
static void qmgr_message_resolve(QMGR_MESSAGE *message) { static ARGV *defer_xport_argv; RECIPIENT_LIST list = message->rcpt_list; RECIPIENT *recipient; QMGR_TRANSPORT *transport = 0; QMGR_QUEUE *queue = 0; RESOLVE_REPLY reply; VSTRING *queue_name; char *at; char **cpp; char *nexthop; ssize_t len; int status; DSN dsn; MSG_STATS stats; DSN *saved_dsn; #define STREQ(x,y) (strcmp(x,y) == 0) #define STR vstring_str #define LEN VSTRING_LEN resolve_clnt_init(&reply); queue_name = vstring_alloc(1); for (recipient = list.info; recipient < list.info + list.len; recipient++) { /* * Redirect overrides all else. But only once (per entire message). * For consistency with the remainder of Postfix, rewrite the address * to canonical form before resolving it. */ if (message->redirect_addr) { if (recipient > list.info) { recipient->u.queue = 0; continue; } message->rcpt_offset = 0; message->rcpt_unread = 0; rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr, reply.recipient); RECIPIENT_UPDATE(recipient->address, STR(reply.recipient)); if (qmgr_resolve_one(message, recipient, recipient->address, &reply) < 0) continue; if (!STREQ(recipient->address, STR(reply.recipient))) RECIPIENT_UPDATE(recipient->address, STR(reply.recipient)); } /* * Content filtering overrides the address resolver. * * XXX Bypass content_filter inspection for user-generated probes * (sendmail -bv). MTA-generated probes never have the "please filter * me" bits turned on, but we handle them here anyway for the sake of * future proofing. */ #define FILTER_WITHOUT_NEXTHOP(filter, next) \ (((next) = split_at((filter), ':')) == 0 || *(next) == 0) #define RCPT_WITHOUT_DOMAIN(rcpt, next) \ ((next = strrchr(rcpt, '@')) == 0 || *++(next) == 0) else if (message->filter_xport && (message->tflags & DEL_REQ_TRACE_ONLY_MASK) == 0) { reply.flags = 0; vstring_strcpy(reply.transport, message->filter_xport); if (FILTER_WITHOUT_NEXTHOP(STR(reply.transport), nexthop) && *(nexthop = var_def_filter_nexthop) == 0 && RCPT_WITHOUT_DOMAIN(recipient->address, nexthop)) nexthop = var_myhostname; vstring_strcpy(reply.nexthop, nexthop); vstring_strcpy(reply.recipient, recipient->address); } /* * Resolve the destination to (transport, nexthop, address). The * result address may differ from the one specified by the sender. */ else { if (qmgr_resolve_one(message, recipient, recipient->address, &reply) < 0) continue; if (!STREQ(recipient->address, STR(reply.recipient))) RECIPIENT_UPDATE(recipient->address, STR(reply.recipient)); } /* * Bounce null recipients. This should never happen, but is most * likely the result of a fault in a different program, so aborting * the queue manager process does not help. */ if (recipient->address[0] == 0) { QMGR_REDIRECT(&reply, MAIL_SERVICE_ERROR, "5.1.3 null recipient address"); } /* * Discard mail to the local double bounce address here, so this * system can run without a local delivery agent. They'd still have * to configure something for mail directed to the local postmaster, * though, but that is an RFC requirement anyway. * * XXX This lookup should be done in the resolver, and the mail should * be directed to a general-purpose null delivery agent. */ if (reply.flags & RESOLVE_CLASS_LOCAL) { at = strrchr(STR(reply.recipient), '@'); len = (at ? (at - STR(reply.recipient)) : strlen(STR(reply.recipient))); if (strncasecmp(STR(reply.recipient), var_double_bounce_sender, len) == 0 && !var_double_bounce_sender[len]) { status = sent(message->tflags, message->queue_id, QMGR_MSG_STATS(&stats, message), recipient, "none", DSN_SIMPLE(&dsn, "2.0.0", "undeliverable postmaster notification discarded")); if (status == 0) { deliver_completed(message->fp, recipient->offset); #if 0 /* It's the default verification probe sender address. */ msg_warn("%s: undeliverable postmaster notification discarded", message->queue_id); #endif } else message->flags |= status; continue; } } /* * Optionally defer deliveries over specific transports, unless the * restriction is lifted temporarily. */ if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) { if (defer_xport_argv == 0) defer_xport_argv = argv_split(var_defer_xports, CHARS_COMMA_SP); for (cpp = defer_xport_argv->argv; *cpp; cpp++) if (strcmp(*cpp, STR(reply.transport)) == 0) break; if (*cpp) { QMGR_REDIRECT(&reply, MAIL_SERVICE_RETRY, "4.3.2 deferred transport"); } } /* * Look up or instantiate the proper transport. */ if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) { if ((transport = qmgr_transport_find(STR(reply.transport))) == 0) transport = qmgr_transport_create(STR(reply.transport)); queue = 0; } /* * This message is being flushed. If need-be unthrottle the * transport. */ if ((message->qflags & QMGR_FLUSH_EACH) != 0 && QMGR_TRANSPORT_THROTTLED(transport)) qmgr_transport_unthrottle(transport); /* * This transport is dead. Defer delivery to this recipient. */ if (QMGR_TRANSPORT_THROTTLED(transport)) { saved_dsn = transport->dsn; if ((transport = qmgr_error_transport(MAIL_SERVICE_RETRY)) != 0) { nexthop = qmgr_error_nexthop(saved_dsn); vstring_strcpy(reply.nexthop, nexthop); myfree(nexthop); queue = 0; } else { qmgr_defer_recipient(message, recipient, saved_dsn); continue; } } /* * The nexthop destination provides the default name for the * per-destination queue. When the delivery agent accepts only one * recipient per delivery, give each recipient its own queue, so that * deliveries to different recipients of the same message can happen * in parallel, and so that we can enforce per-recipient concurrency * limits and prevent one recipient from tying up all the delivery * agent resources. We use recipient@nexthop as queue name rather * than the actual recipient domain name, so that one recipient in * multiple equivalent domains cannot evade the per-recipient * concurrency limit. Split the address on the recipient delimiter if * one is defined, so that extended addresses don't get extra * delivery slots. * * Fold the result to lower case so that we don't have multiple queues * for the same name. * * Important! All recipients in a queue must have the same nexthop * value. It is OK to have multiple queues with the same nexthop * value, but only when those queues are named after recipients. * * The single-recipient code below was written for local(8) like * delivery agents, and assumes that all domains that deliver to the * same (transport + nexthop) are aliases for $nexthop. Delivery * concurrency is changed from per-domain into per-recipient, by * changing the queue name from nexthop into localpart@nexthop. * * XXX This assumption is incorrect when different destinations share * the same (transport + nexthop). In reality, such transports are * rarely configured to use single-recipient deliveries. The fix is * to decouple the per-destination recipient limit from the * per-destination concurrency. */ vstring_strcpy(queue_name, STR(reply.nexthop)); if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0 && strcmp(transport->name, MAIL_SERVICE_RETRY) != 0 && transport->recipient_limit == 1) { /* Copy the recipient localpart. */ at = strrchr(STR(reply.recipient), '@'); len = (at ? (at - STR(reply.recipient)) : strlen(STR(reply.recipient))); vstring_strncpy(queue_name, STR(reply.recipient), len); /* Remove the address extension from the recipient localpart. */ if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim)) vstring_truncate(queue_name, strlen(STR(queue_name))); /* Assume the recipient domain is equivalent to nexthop. */ vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop)); } lowercase(STR(queue_name)); /* * This transport is alive. Find or instantiate a queue for this * recipient. */ if (queue == 0 || !STREQ(queue->name, STR(queue_name))) { if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0) queue = qmgr_queue_create(transport, STR(queue_name), STR(reply.nexthop)); } /* * This message is being flushed. If need-be unthrottle the queue. */ if ((message->qflags & QMGR_FLUSH_EACH) != 0 && QMGR_QUEUE_THROTTLED(queue)) qmgr_queue_unthrottle(queue); /* * This queue is dead. Defer delivery to this recipient. */ if (QMGR_QUEUE_THROTTLED(queue)) { saved_dsn = queue->dsn; if ((queue = qmgr_error_queue(MAIL_SERVICE_RETRY, saved_dsn)) == 0) { qmgr_defer_recipient(message, recipient, saved_dsn); continue; } } /* * This queue is alive. Bind this recipient to this queue instance. */ recipient->u.queue = queue; } resolve_clnt_free(&reply); vstring_free(queue_name); }