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 messages_list(
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) {
53 self.max_results = value;
54 }
55
56 fn max_results(&self) -> u32 {
58 self.max_results
59 }
60
61 fn add_labels(&mut self, labels: &[String]) -> Result<()> {
63 log::debug!("labels from command line: {labels:?}");
64 let mut label_ids = Vec::new();
65 for label in labels {
66 if let Some(id) = self.get_label_id(label) {
67 label_ids.push(id)
68 }
69 }
70 self.add_labels_ids(label_ids.as_slice());
71 Ok(())
72 }
73
74 fn add_labels_ids(&mut self, label_ids: &[String]) {
76 if !label_ids.is_empty() {
77 for id in label_ids {
78 self.label_ids.push(id.to_string())
79 }
80 }
81 }
82
83 fn set_query(&mut self, query: &str) {
85 self.query = query.to_string()
86 }
87
88 fn messages(&self) -> &Vec<MessageSummary> {
90 &self.messages
91 }
92
93 fn message_ids(&self) -> Vec<String> {
95 self.messages
96 .iter()
97 .map(|m| m.id().to_string())
98 .collect::<Vec<_>>()
99 .clone()
100 }
101
102 fn label_ids(&self) -> Vec<String> {
104 self.label_ids.clone()
105 }
106
107 fn hub(&self) -> Gmail<HttpsConnector<HttpConnector>> {
109 self.hub().clone()
110 }
111
112 async fn get_messages(&mut self, pages: u32) -> Result<()> {
114 let list = self.messages_list(None).await?;
115 match pages {
116 1 => {}
117 0 => {
118 let mut list = list;
119 let mut page = 1;
120 loop {
121 page += 1;
122 log::debug!("Processing page #{page}");
123 if list.next_page_token.is_none() {
124 break;
125 }
126 list = self.messages_list(list.next_page_token).await?;
127 }
129 }
130 _ => {
131 let mut list = list;
132 for page in 2..=pages {
133 log::debug!("Processing page #{page}");
134 if list.next_page_token.is_none() {
135 break;
136 }
137 list = self.messages_list(list.next_page_token).await?;
138 }
140 }
141 }
142
143 Ok(())
144 }
145
146 async fn messages_list(
147 &mut self,
148 next_page_token: Option<String>,
149 ) -> Result<ListMessagesResponse> {
150 let hub = self.hub();
151 let mut call = hub
152 .users()
153 .messages_list("me")
154 .max_results(self.max_results);
155 if !self.label_ids.is_empty() {
157 log::debug!("Setting labels for list: {:#?}", self.label_ids);
158 for id in self.label_ids.as_slice() {
159 call = call.add_label_ids(id);
160 }
161 }
162 if !self.query.is_empty() {
164 log::debug!("Setting query string `{}`", self.query);
165 call = call.q(&self.query);
166 }
167 if let Some(page_token) = next_page_token {
169 log::debug!("Setting token for next page.");
170 call = call.page_token(&page_token);
171 }
172
173 let (_response, list) = call.doit().await.map_err(Box::new)?;
174 log::trace!(
175 "Estimated {} messages.",
176 list.result_size_estimate.unwrap_or(0)
177 );
178
179 if list.result_size_estimate.unwrap_or(0) == 0 {
180 log::warn!("Search returned no messages.");
181 return Ok(list);
182 }
183
184 let mut list_ids = list
185 .clone()
186 .messages
187 .unwrap()
188 .iter()
189 .flat_map(|item| item.id.as_ref().map(|id| MessageSummary::new(id)))
190 .collect();
191 self.messages.append(&mut list_ids);
192
193 Ok(list)
194 }
195
196 async fn log_messages(&mut self) -> Result<()> {
197 let hub = self.hub();
198 for message in &mut self.messages {
199 log::trace!("{}", message.id());
200 let (_res, m) = hub
201 .users()
202 .messages_get("me", message.id())
203 .add_scope("https://mail.google.com/")
204 .format("metadata")
205 .add_metadata_headers("subject")
206 .add_metadata_headers("date")
207 .doit()
208 .await
209 .map_err(Box::new)?;
210
211 let Some(payload) = m.payload else { continue };
212 let Some(headers) = payload.headers else {
213 continue;
214 };
215
216 for header in headers {
217 if let Some(name) = header.name {
218 match name.to_lowercase().as_str() {
219 "subject" => message.set_subject(header.value),
220 "date" => message.set_date(header.value),
221 _ => {}
222 }
223 } else {
224 continue;
225 }
226 }
227
228 log::info!("{}", message.list_date_and_subject());
229 }
230
231 Ok(())
232 }
233}