cull_gmail/
message_list.rs1use crate::{GmailClient, MessageSummary, Result};
2
3use google_gmail1::{
4 Gmail, api::ListMessagesResponse, hyper_rustls::HttpsConnector,
5 hyper_util::client::legacy::connect::HttpConnector,
6};
7
8pub trait MessageList {
10 fn log_messages(&mut self) -> impl std::future::Future<Output = Result<()>> + Send;
12 fn list_messages(
14 &mut self,
15 next_page_token: Option<String>,
16 ) -> impl std::future::Future<Output = Result<ListMessagesResponse>> + Send;
17 fn get_messages(&mut self, pages: u32) -> impl std::future::Future<Output = Result<()>> + Send;
19 fn hub(&self) -> Gmail<HttpsConnector<HttpConnector>>;
21 fn label_ids(&self) -> Vec<String>;
23 fn message_ids(&self) -> Vec<String>;
25 fn messages(&self) -> &Vec<MessageSummary>;
27 fn set_query(&mut self, query: &str);
29 fn add_labels_ids(&mut self, label_ids: &[String]);
31 fn add_labels(&mut self, labels: &[String]) -> Result<()>;
33 fn max_results(&self) -> u32;
35 fn set_max_results(&mut self, value: u32);
37}
38
39impl MessageList for GmailClient {
40 fn set_max_results(&mut self, value: u32) {
42 self.max_results = value;
43 }
44
45 fn max_results(&self) -> u32 {
47 self.max_results
48 }
49
50 fn add_labels(&mut self, labels: &[String]) -> Result<()> {
52 log::debug!("labels from command line: {labels:?}");
53 let mut label_ids = Vec::new();
54 for label in labels {
55 if let Some(id) = self.get_label_id(label) {
56 label_ids.push(id)
57 }
58 }
59 self.add_labels_ids(label_ids.as_slice());
60 Ok(())
61 }
62
63 fn add_labels_ids(&mut self, label_ids: &[String]) {
65 if !label_ids.is_empty() {
66 for id in label_ids {
67 self.label_ids.push(id.to_string())
68 }
69 }
70 }
71
72 fn set_query(&mut self, query: &str) {
74 self.query = query.to_string()
75 }
76
77 fn messages(&self) -> &Vec<MessageSummary> {
79 &self.messages
80 }
81
82 fn message_ids(&self) -> Vec<String> {
84 self.messages
85 .iter()
86 .map(|m| m.id().to_string())
87 .collect::<Vec<_>>()
88 .clone()
89 }
90
91 fn label_ids(&self) -> Vec<String> {
93 self.label_ids.clone()
94 }
95
96 fn hub(&self) -> Gmail<HttpsConnector<HttpConnector>> {
98 self.hub().clone()
99 }
100
101 async fn get_messages(&mut self, pages: u32) -> Result<()> {
103 let list = self.list_messages(None).await?;
104 match pages {
105 1 => {}
106 0 => {
107 let mut list = list;
108 let mut page = 1;
109 loop {
110 page += 1;
111 log::debug!("Processing page #{page}");
112 if list.next_page_token.is_none() {
113 break;
114 }
115 list = self.list_messages(list.next_page_token).await?;
116 }
118 }
119 _ => {
120 let mut list = list;
121 for page in 2..=pages {
122 log::debug!("Processing page #{page}");
123 if list.next_page_token.is_none() {
124 break;
125 }
126 list = self.list_messages(list.next_page_token).await?;
127 }
129 }
130 }
131
132 Ok(())
133 }
134
135 async fn list_messages(
136 &mut self,
137 next_page_token: Option<String>,
138 ) -> Result<ListMessagesResponse> {
139 let hub = self.hub();
140 let mut call = hub
141 .users()
142 .messages_list("me")
143 .max_results(self.max_results);
144 if !self.label_ids.is_empty() {
146 log::debug!("Setting labels for list: {:#?}", self.label_ids);
147 for id in self.label_ids.as_slice() {
148 call = call.add_label_ids(id);
149 }
150 }
151 if !self.query.is_empty() {
153 log::debug!("Setting query string `{}`", self.query);
154 call = call.q(&self.query);
155 }
156 if let Some(page_token) = next_page_token {
158 log::debug!("Setting token for next page.");
159 call = call.page_token(&page_token);
160 }
161
162 let (_response, list) = call.doit().await.map_err(Box::new)?;
163 log::trace!(
164 "Estimated {} messages.",
165 list.result_size_estimate.unwrap_or(0)
166 );
167
168 if list.result_size_estimate.unwrap_or(0) == 0 {
169 log::warn!("Search returned no messages.");
170 return Ok(list);
171 }
172
173 let mut list_ids = list
174 .clone()
175 .messages
176 .unwrap()
177 .iter()
178 .flat_map(|item| item.id.as_ref().map(|id| MessageSummary::new(id)))
179 .collect();
180 self.messages.append(&mut list_ids);
181
182 Ok(list)
183 }
184
185 async fn log_messages(&mut self) -> Result<()> {
186 let hub = self.hub();
187 for message in &mut self.messages {
188 log::trace!("{}", message.id());
189 let (_res, m) = hub
190 .users()
191 .messages_get("me", message.id())
192 .add_scope("https://mail.google.com/")
193 .format("metadata")
194 .add_metadata_headers("subject")
195 .add_metadata_headers("date")
196 .doit()
197 .await
198 .map_err(Box::new)?;
199
200 let Some(payload) = m.payload else { continue };
201 let Some(headers) = payload.headers else {
202 continue;
203 };
204
205 for header in headers {
206 if let Some(name) = header.name {
207 match name.to_lowercase().as_str() {
208 "subject" => message.set_subject(header.value),
209 "date" => message.set_date(header.value),
210 _ => {}
211 }
212 } else {
213 continue;
214 }
215 }
216
217 log::info!("{}", message.list_date_and_subject());
218 }
219
220 Ok(())
221 }
222}