1
3
/*
2
 * This file is part of mailpot
3
 *
4
 * Copyright 2020 - Manos Pitsidianakis
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as
8
 * published by the Free Software Foundation, either version 3 of the
9
 * License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18
 */
19

            
20
#![deny(
21
    missing_docs,
22
    rustdoc::broken_intra_doc_links,
23
    /* groups */
24
    clippy::correctness,
25
    clippy::suspicious,
26
    clippy::complexity,
27
    clippy::perf,
28
    clippy::style,
29
    clippy::cargo,
30
    clippy::nursery,
31
    /* restriction */
32
    clippy::dbg_macro,
33
    clippy::rc_buffer,
34
    clippy::as_underscore,
35
    clippy::assertions_on_result_states,
36
    /* pedantic */
37
    clippy::cast_lossless,
38
    clippy::cast_possible_wrap,
39
    clippy::ptr_as_ptr,
40
    clippy::bool_to_int_with_if,
41
    clippy::borrow_as_ptr,
42
    clippy::case_sensitive_file_extension_comparisons,
43
    clippy::cast_lossless,
44
    clippy::cast_ptr_alignment,
45
    clippy::naive_bytecount
46
)]
47
#![allow(clippy::multiple_crate_versions, clippy::missing_const_for_fn)]
48

            
49
//! Mailing list manager library.
50
//!
51
//! ```
52
//! use mailpot::{models::*, Configuration, Connection, SendMail};
53
//! # use tempfile::TempDir;
54
//!
55
//! # let tmp_dir = TempDir::new().unwrap();
56
//! # let db_path = tmp_dir.path().join("mpot.db");
57
//! # let config = Configuration {
58
//! #     send_mail: SendMail::ShellCommand("/usr/bin/false".to_string()),
59
//! #     db_path: db_path.clone(),
60
//! #     data_path: tmp_dir.path().to_path_buf(),
61
//! #     administrators: vec![],
62
//! # };
63
//! #
64
//! # fn do_test(config: Configuration) -> mailpot::Result<()> {
65
//! let db = Connection::open_or_create_db(config)?.trusted();
66
//!
67
//! // Create a new mailing list
68
//! let list_pk = db
69
//!     .create_list(MailingList {
70
//!         pk: 0,
71
//!         name: "foobar chat".into(),
72
//!         id: "foo-chat".into(),
73
//!         address: "foo-chat@example.com".into(),
74
//!         description: None,
75
//!         archive_url: None,
76
//!     })?
77
//!     .pk;
78
//!
79
//! db.set_list_post_policy(PostPolicy {
80
//!     pk: 0,
81
//!     list: list_pk,
82
//!     announce_only: false,
83
//!     subscription_only: true,
84
//!     approval_needed: false,
85
//!     open: false,
86
//!     custom: false,
87
//! })?;
88
//!
89
//! // Drop privileges; we can only process new e-mail and modify subscriptions from now on.
90
//! let mut db = db.untrusted();
91
//!
92
//! assert_eq!(db.list_subscriptions(list_pk)?.len(), 0);
93
//! assert_eq!(db.list_posts(list_pk, None)?.len(), 0);
94
//!
95
//! // Process a subscription request e-mail
96
//! let subscribe_bytes = b"From: Name <user@example.com>
97
//! To: <foo-chat+subscribe@example.com>
98
//! Subject: subscribe
99
//! Date: Thu, 29 Oct 2020 13:58:16 +0000
100
//! Message-ID: <1@example.com>
101
//!
102
//! ";
103
//! let envelope = melib::Envelope::from_bytes(subscribe_bytes, None)?;
104
//! db.post(&envelope, subscribe_bytes, /* dry_run */ false)?;
105
//!
106
//! assert_eq!(db.list_subscriptions(list_pk)?.len(), 1);
107
//! assert_eq!(db.list_posts(list_pk, None)?.len(), 0);
108
//!
109
//! // Process a post
110
//! let post_bytes = b"From: Name <user@example.com>
111
//! To: <foo-chat@example.com>
112
//! Subject: my first post
113
//! Date: Thu, 29 Oct 2020 14:01:09 +0000
114
//! Message-ID: <2@example.com>
115
//!
116
//! Hello
117
//! ";
118
//! let envelope = melib::Envelope::from_bytes(post_bytes, None).expect("Could not parse message");
119
//! db.post(&envelope, post_bytes, /* dry_run */ false)?;
120
//!
121
//! assert_eq!(db.list_subscriptions(list_pk)?.len(), 1);
122
//! assert_eq!(db.list_posts(list_pk, None)?.len(), 1);
123
//! # Ok(())
124
//! # }
125
//! # do_test(config);
126
//! ```
127

            
128
/* Annotations:
129
 *
130
 * Global tags (in tagref format <https://github.com/stepchowfun/tagref>) for source code
131
 * annotation:
132
 *
133
 * - [tag:needs_unit_test]
134
 * - [tag:needs_user_doc]
135
 * - [tag:needs_dev_doc]
136
 * - [tag:FIXME]
137
 * - [tag:TODO]
138
 * - [tag:VERIFY] Verify whether this is the correct way to do something
139
 */
140

            
141
#[macro_use]
142
extern crate error_chain;
143
pub extern crate anyhow;
144
pub extern crate rusqlite;
145

            
146
#[macro_use]
147
pub extern crate serde;
148
pub extern crate log;
149
pub extern crate melib;
150
pub extern crate serde_json;
151

            
152
use log::{info, trace};
153

            
154
mod config;
155
mod db;
156
mod errors;
157
pub mod mail;
158
pub mod models;
159
#[cfg(not(target_os = "windows"))]
160
pub mod postfix;
161
pub mod submission;
162
mod templates;
163

            
164
pub use config::{Configuration, SendMail};
165
pub use db::*;
166
pub use errors::*;
167
use models::*;
168
pub use templates::*;
169

            
170
/// A `mailto:` value.
171
#[derive(Debug, Clone, Deserialize, Serialize)]
172
pub struct MailtoAddress {
173
    /// E-mail address.
174
    pub address: String,
175
    /// Optional subject value.
176
    pub subject: Option<String>,
177
}
178

            
179
#[doc = include_str!("../../README.md")]
180
#[cfg(doctest)]
181
pub struct ReadmeDoctests;