Files
herolib/lib/vfs/vfs_mail/vfs_implementation.v
2025-03-15 19:32:38 +01:00

439 lines
10 KiB
V

module vfs_mail
import json
import os
import time
import freeflowuniverse.herolib.vfs
import freeflowuniverse.herolib.circles.models.mail
import freeflowuniverse.herolib.circles.dbs.core
import freeflowuniverse.herolib.core.texttools
// Basic operations
pub fn (mut myvfs MailVFS) root_get() !vfs.FSEntry {
metadata := vfs.Metadata{
id: 1
name: ''
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
return MailFSEntry{
path: ''
metadata: metadata
}
}
// File operations
pub fn (mut myvfs MailVFS) file_create(path string) !vfs.FSEntry {
return error('Mail VFS is read-only')
}
pub fn (mut myvfs MailVFS) file_read(path string) ![]u8 {
if !myvfs.exists(path) {
return error('File does not exist: ${path}')
}
entry := myvfs.get(path)!
if !entry.is_file() {
return error('Path is not a file: ${path}')
}
mail_entry := entry as MailFSEntry
if email := mail_entry.email {
return json.encode(email).bytes()
}
return error('Failed to read file: ${path}')
}
pub fn (mut myvfs MailVFS) file_write(path string, data []u8) ! {
return error('Mail VFS is read-only')
}
pub fn (mut myvfs MailVFS) file_concatenate(path string, data []u8) ! {
return error('Mail VFS is read-only')
}
pub fn (mut myvfs MailVFS) file_delete(path string) ! {
return error('Mail VFS is read-only')
}
// Directory operations
pub fn (mut myvfs MailVFS) dir_create(path string) !vfs.FSEntry {
return error('Mail VFS is read-only')
}
pub fn (mut myvfs MailVFS) dir_list(path string) ![]vfs.FSEntry {
if !myvfs.exists(path) {
return error('Directory does not exist: ${path}')
}
// Get all emails
emails := myvfs.mail_db.getall() or { return error('Failed to get emails: ${err}') }
// If we're at the root, return all mailboxes
if path == '' {
return myvfs.list_mailboxes(emails)!
}
// Check if we're in a mailbox path
path_parts := path.split('/')
if path_parts.len == 1 {
// We're in a mailbox, show the id and subject directories
return myvfs.list_mailbox_subdirs(path)!
} else if path_parts.len == 2 && path_parts[1] in ['id', 'subject'] {
// We're in an id or subject directory, list the emails
return myvfs.list_emails_by_type(path_parts[0], path_parts[1], emails)!
}
return []vfs.FSEntry{}
}
pub fn (mut myvfs MailVFS) dir_delete(path string) ! {
return error('Mail VFS is read-only')
}
// Symlink operations
pub fn (mut myvfs MailVFS) link_create(target_path string, link_path string) !vfs.FSEntry {
return error('Mail VFS does not support symlinks')
}
pub fn (mut myvfs MailVFS) link_read(path string) !string {
return error('Mail VFS does not support symlinks')
}
pub fn (mut myvfs MailVFS) link_delete(path string) ! {
return error('Mail VFS does not support symlinks')
}
// Common operations
pub fn (mut myvfs MailVFS) exists(path string) bool {
// Root always exists
if path == '' {
return true
}
// Get all emails
emails := myvfs.mail_db.getall() or { return false }
// Debug print
if path.contains('subject') {
println('Checking exists for path: ${path}')
}
path_parts := path.split('/')
// Check if the path is a mailbox
if path_parts.len == 1 {
for email in emails {
mailbox_parts := email.mailbox.split('/')
if mailbox_parts.len > 0 && mailbox_parts[0] == path_parts[0] {
return true
}
}
}
// Check if the path is a mailbox subdir (id or subject)
if path_parts.len == 2 && path_parts[1] in ['id', 'subject'] {
for email in emails {
mailbox_parts := email.mailbox.split('/')
if mailbox_parts.len > 0 && mailbox_parts[0] == path_parts[0] {
return true
}
}
}
// Check if the path is an email file
if path_parts.len == 3 && path_parts[1] in ['id', 'subject'] {
for email in emails {
if email.mailbox.split('/')[0] != path_parts[0] {
continue
}
if path_parts[1] == 'id' && '${email.id}.json' == path_parts[2] {
return true
} else if path_parts[1] == 'subject' {
if envelope := email.envelope {
subject_filename := texttools.name_fix(envelope.subject) + '.json'
if path.contains('subject') {
println('Comparing: "${path_parts[2]}" with "${subject_filename}"')
println('Original subject: "${envelope.subject}"')
println('After name_fix: "${texttools.name_fix(envelope.subject)}"')
}
if subject_filename == path_parts[2] {
return true
}
}
}
}
}
return false
}
pub fn (mut myvfs MailVFS) get(path string) !vfs.FSEntry {
// Root always exists
if path == '' {
return myvfs.root_get()!
}
// Debug print
println('Getting path: ${path}')
// Get all emails
emails := myvfs.mail_db.getall() or { return error('Failed to get emails: ${err}') }
// Debug: Print all emails
println('All emails in DB:')
for email in emails {
if envelope := email.envelope {
println('Email ID: ${email.id}, Subject: "${envelope.subject}", Mailbox: ${email.mailbox}')
}
}
path_parts := path.split('/')
// Check if the path is a mailbox
if path_parts.len == 1 {
for email in emails {
mailbox_parts := email.mailbox.split('/')
if mailbox_parts.len > 0 && mailbox_parts[0] == path_parts[0] {
metadata := vfs.Metadata{
id: u32(path_parts[0].bytes().bytestr().hash())
name: path_parts[0]
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
return MailFSEntry{
path: path
metadata: metadata
}
}
}
}
// Check if the path is a mailbox subdir (id or subject)
if path_parts.len == 2 && path_parts[1] in ['id', 'subject'] {
metadata := vfs.Metadata{
id: u32(path.bytes().bytestr().hash())
name: path_parts[1]
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
return MailFSEntry{
path: path
metadata: metadata
}
}
// Check if the path is an email file
if path_parts.len == 3 && path_parts[1] in ['id', 'subject'] {
for email in emails {
if email.mailbox.split('/')[0] != path_parts[0] {
continue
}
if path_parts[1] == 'id' && '${email.id}.json' == path_parts[2] {
metadata := vfs.Metadata{
id: email.id
name: '${email.id}.json'
file_type: .file
size: u64(json.encode(email).len)
created_at: email.internal_date
modified_at: email.internal_date
accessed_at: time.now().unix()
}
return MailFSEntry{
path: path
metadata: metadata
email: email
}
} else if path_parts[1] == 'subject' {
if envelope := email.envelope {
subject_filename := texttools.name_fix(envelope.subject) + '.json'
if subject_filename == path_parts[2] {
metadata := vfs.Metadata{
id: email.id
name: subject_filename
file_type: .file
size: u64(json.encode(email).len)
created_at: email.internal_date
modified_at: email.internal_date
accessed_at: time.now().unix()
}
return MailFSEntry{
path: path
metadata: metadata
email: email
}
}
}
}
}
}
return error('Path not found: ${path}')
}
pub fn (mut myvfs MailVFS) rename(old_path string, new_path string) !vfs.FSEntry {
return error('Mail VFS is read-only')
}
pub fn (mut myvfs MailVFS) copy(src_path string, dst_path string) !vfs.FSEntry {
return error('Mail VFS is read-only')
}
pub fn (mut myvfs MailVFS) move(src_path string, dst_path string) !vfs.FSEntry {
return error('Mail VFS is read-only')
}
pub fn (mut myvfs MailVFS) delete(path string) ! {
return error('Mail VFS is read-only')
}
// FSEntry Operations
pub fn (mut myvfs MailVFS) get_path(entry &vfs.FSEntry) !string {
mail_entry := entry as MailFSEntry
return mail_entry.path
}
pub fn (mut myvfs MailVFS) print() ! {
println('Mail VFS')
}
// Cleanup operation
pub fn (mut myvfs MailVFS) destroy() ! {
// Nothing to clean up
}
// Helper functions
fn (mut myvfs MailVFS) list_mailboxes(emails []mail.Email) ![]vfs.FSEntry {
mut mailboxes := map[string]bool{}
// Collect unique top-level mailbox names
for email in emails {
mailbox_parts := email.mailbox.split('/')
if mailbox_parts.len > 0 {
mailboxes[mailbox_parts[0]] = true
}
}
// Create FSEntry for each mailbox
mut result := []vfs.FSEntry{cap: mailboxes.len}
for mailbox, _ in mailboxes {
metadata := vfs.Metadata{
id: u32(mailbox.bytes().bytestr().hash())
name: mailbox
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << MailFSEntry{
path: mailbox
metadata: metadata
}
}
return result
}
fn (mut myvfs MailVFS) list_mailbox_subdirs(mailbox string) ![]vfs.FSEntry {
mut result := []vfs.FSEntry{cap: 2}
// Create id directory
id_metadata := vfs.Metadata{
id: u32('${mailbox}/id'.bytes().bytestr().hash())
name: 'id'
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << MailFSEntry{
path: '${mailbox}/id'
metadata: id_metadata
}
// Create subject directory
subject_metadata := vfs.Metadata{
id: u32('${mailbox}/subject'.bytes().bytestr().hash())
name: 'subject'
file_type: .directory
created_at: time.now().unix()
modified_at: time.now().unix()
accessed_at: time.now().unix()
}
result << MailFSEntry{
path: '${mailbox}/subject'
metadata: subject_metadata
}
return result
}
fn (mut myvfs MailVFS) list_emails_by_type(mailbox string, list_type string, emails []mail.Email) ![]vfs.FSEntry {
mut result := []vfs.FSEntry{}
for email in emails {
if email.mailbox.split('/')[0] != mailbox {
continue
}
if list_type == 'id' {
filename := '${email.id}.json'
metadata := vfs.Metadata{
id: email.id
name: filename
file_type: .file
size: u64(json.encode(email).len)
created_at: email.internal_date
modified_at: email.internal_date
accessed_at: time.now().unix()
}
result << MailFSEntry{
path: '${mailbox}/id/${filename}'
metadata: metadata
email: email
}
} else if list_type == 'subject' {
if envelope := email.envelope {
filename := texttools.name_fix(envelope.subject) + '.json'
metadata := vfs.Metadata{
id: email.id
name: filename
file_type: .file
size: u64(json.encode(email).len)
created_at: email.internal_date
modified_at: email.internal_date
accessed_at: time.now().unix()
}
result << MailFSEntry{
path: '${mailbox}/subject/${filename}'
metadata: metadata
email: email
}
}
}
}
return result
}