|
@@ -10,26 +10,30 @@ use std::io::{BufReader, Write};
|
|
use std::net::SocketAddr;
|
|
use std::net::SocketAddr;
|
|
use std::time::Duration;
|
|
use std::time::Duration;
|
|
use anyhow::anyhow;
|
|
use anyhow::anyhow;
|
|
-use serde::Deserialize;
|
|
|
|
|
|
+use serde::{Deserialize, Serialize};
|
|
use crate::indexes::{Indexes, SerializableMessage, SerializableThread};
|
|
use crate::indexes::{Indexes, SerializableMessage, SerializableThread};
|
|
use config::{Config, INSTANCE};
|
|
use config::{Config, INSTANCE};
|
|
use crate::server::{get_email, get_folders, get_sorted_threads_by_date, get_thread_messages};
|
|
use crate::server::{get_email, get_folders, get_sorted_threads_by_date, get_thread_messages};
|
|
use mailparse::parse_mail;
|
|
use mailparse::parse_mail;
|
|
use regex::Regex;
|
|
use regex::Regex;
|
|
use crate::templates::util::parse_email;
|
|
use crate::templates::util::parse_email;
|
|
|
|
+use crate::util::{compress_and_save_file, read_and_decompress_file};
|
|
|
|
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[cfg(not(target_os = "wasi"))]
|
|
use axum::extract::Query;
|
|
use axum::extract::Query;
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[cfg(not(target_os = "wasi"))]
|
|
use axum::{Json, Router};
|
|
use axum::{Json, Router};
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[cfg(not(target_os = "wasi"))]
|
|
-use axum::http::Method;
|
|
|
|
|
|
+use axum::http::{Method, StatusCode};
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[cfg(not(target_os = "wasi"))]
|
|
use axum::response::{IntoResponse, Response};
|
|
use axum::response::{IntoResponse, Response};
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[cfg(not(target_os = "wasi"))]
|
|
use axum::routing::{get, post};
|
|
use axum::routing::{get, post};
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[cfg(not(target_os = "wasi"))]
|
|
use tower_http::cors::{Any, CorsLayer};
|
|
use tower_http::cors::{Any, CorsLayer};
|
|
|
|
+#[cfg(not(target_os = "wasi"))]
|
|
|
|
+use imap::create_folder;
|
|
|
|
+
|
|
|
|
|
|
#[cfg(target_os = "wasi")]
|
|
#[cfg(target_os = "wasi")]
|
|
use bytecodec::DecodeExt;
|
|
use bytecodec::DecodeExt;
|
|
@@ -38,14 +42,13 @@ use httpcodec::{HttpVersion, ReasonPhrase, Request, RequestDecoder, Response, St
|
|
#[cfg(target_os = "wasi")]
|
|
#[cfg(target_os = "wasi")]
|
|
use lettre::message::{Mailbox, Message as LettreMessage, MultiPart, SinglePart};
|
|
use lettre::message::{Mailbox, Message as LettreMessage, MultiPart, SinglePart};
|
|
use tokio::runtime::Runtime;
|
|
use tokio::runtime::Runtime;
|
|
-use tokio::time::sleep;
|
|
|
|
#[cfg(target_os = "wasi")]
|
|
#[cfg(target_os = "wasi")]
|
|
use wasmedge_wasi_socket::{Shutdown, TcpListener, TcpStream};
|
|
use wasmedge_wasi_socket::{Shutdown, TcpListener, TcpStream};
|
|
|
|
+use crate::imap::{delete_folder, rename_folder};
|
|
#[cfg(target_os = "wasi")]
|
|
#[cfg(target_os = "wasi")]
|
|
use crate::server_wasi::{handle_client};
|
|
use crate::server_wasi::{handle_client};
|
|
#[cfg(target_os = "wasi")]
|
|
#[cfg(target_os = "wasi")]
|
|
use crate::smtp_client::{send_email};
|
|
use crate::smtp_client::{send_email};
|
|
-use crate::util::{compress_and_save_file, read_and_decompress_file};
|
|
|
|
|
|
|
|
mod smtp_client;
|
|
mod smtp_client;
|
|
|
|
|
|
@@ -393,7 +396,7 @@ async fn main() {
|
|
|
|
|
|
// looking for updates
|
|
// looking for updates
|
|
// let imap_update_handle = tokio::spawn(async move {
|
|
// let imap_update_handle = tokio::spawn(async move {
|
|
- // imap::check_for_updates("INBOX".to_string()).await.expect("TODO: panic message");
|
|
|
|
|
|
+ // imap::check_for_updates("INBOX".to_string()).await.expect("panic message");
|
|
// });
|
|
// });
|
|
|
|
|
|
|
|
|
|
@@ -415,6 +418,9 @@ async fn main() {
|
|
.route("/sorted_threads_by_date", get(sorted_threads_by_date_handle))
|
|
.route("/sorted_threads_by_date", get(sorted_threads_by_date_handle))
|
|
.route("/get_thread_messages", get(get_thread_messages_handle))
|
|
.route("/get_thread_messages", get(get_thread_messages_handle))
|
|
.route("/email", get(get_email_handle))
|
|
.route("/email", get(get_email_handle))
|
|
|
|
+ .route("/create_folder", post(create_folder_handle))
|
|
|
|
+ .route("/rename_folder", post(rename_folder_handle))
|
|
|
|
+ .route("/delete_folder", post(delete_folder_handle))
|
|
.layer(cors);
|
|
.layer(cors);
|
|
|
|
|
|
|
|
|
|
@@ -431,6 +437,12 @@ async fn main() {
|
|
handle.join().unwrap();
|
|
handle.join().unwrap();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#[derive(Deserialize)]
|
|
|
|
+#[derive(Serialize)]
|
|
|
|
+struct ErrorResponse {
|
|
|
|
+ error: String,
|
|
|
|
+}
|
|
|
|
+
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[cfg(not(target_os = "wasi"))]
|
|
#[derive(Deserialize)]
|
|
#[derive(Deserialize)]
|
|
struct GetSortedThreadsByDateQuery {
|
|
struct GetSortedThreadsByDateQuery {
|
|
@@ -469,3 +481,64 @@ async fn get_thread_messages_handle(Query(params): Query<GetThreadMessagesQuery>
|
|
let result: Vec<SerializableMessage> = serde_json::from_str(&*get_thread_messages(params.id).await).unwrap();
|
|
let result: Vec<SerializableMessage> = serde_json::from_str(&*get_thread_messages(params.id).await).unwrap();
|
|
Json(result)
|
|
Json(result)
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+#[cfg(not(target_os = "wasi"))]
|
|
|
|
+#[derive(Deserialize)]
|
|
|
|
+struct CreateFolderRequest {
|
|
|
|
+ name: String,
|
|
|
|
+}
|
|
|
|
+#[cfg(not(target_os = "wasi"))]
|
|
|
|
+async fn create_folder_handle(Json(data): Json<CreateFolderRequest>) -> impl IntoResponse {
|
|
|
|
+ match create_folder(data.name.clone()).await {
|
|
|
|
+ Ok(_) => {
|
|
|
|
+ (StatusCode::OK, "OK").into_response()
|
|
|
|
+ }
|
|
|
|
+ Err(_) => {
|
|
|
|
+ let error_response = ErrorResponse {
|
|
|
|
+ error: format!("Cannot create folder {}", data.name),
|
|
|
|
+ };
|
|
|
|
+ (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(not(target_os = "wasi"))]
|
|
|
|
+#[derive(Deserialize)]
|
|
|
|
+struct DeleteFolderRequest {
|
|
|
|
+ name: String,
|
|
|
|
+}
|
|
|
|
+#[cfg(not(target_os = "wasi"))]
|
|
|
|
+async fn delete_folder_handle(Json(data): Json<DeleteFolderRequest>) -> impl IntoResponse {
|
|
|
|
+ match delete_folder(data.name.clone()).await {
|
|
|
|
+ Ok(_) => {
|
|
|
|
+ (StatusCode::OK, "OK").into_response()
|
|
|
|
+ }
|
|
|
|
+ Err(_) => {
|
|
|
|
+ let error_response = ErrorResponse {
|
|
|
|
+ error: format!("Cannot delete folder {}", data.name),
|
|
|
|
+ };
|
|
|
|
+ (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(not(target_os = "wasi"))]
|
|
|
|
+#[derive(Deserialize)]
|
|
|
|
+struct RenameFolderRequest {
|
|
|
|
+ old_name: String,
|
|
|
|
+ new_name: String
|
|
|
|
+}
|
|
|
|
+#[cfg(not(target_os = "wasi"))]
|
|
|
|
+async fn rename_folder_handle(Json(data): Json<RenameFolderRequest>) -> impl IntoResponse {
|
|
|
|
+ match rename_folder(data.old_name.clone(), data.new_name.clone()).await {
|
|
|
|
+ Ok(_) => {
|
|
|
|
+ (StatusCode::OK, "OK").into_response()
|
|
|
|
+ }
|
|
|
|
+ Err(_) => {
|
|
|
|
+ let error_response = ErrorResponse {
|
|
|
|
+ error: format!("Cannot rename folder from {} to {}", data.old_name, data.new_name),
|
|
|
|
+ };
|
|
|
|
+ (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|