2026-08-10 12:52:48 +00:00
package handlers
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"
"sync"
"github.com/go-chi/chi/v5"
"boc/email"
)
var (
mailConfig * MailConfig
mailConfigMu sync . RWMutex
defaultIMAP * email . IMAPClient
)
// MailConfig stores IMAP configuration
type MailConfig struct {
Email string ` json:"email" `
Password string ` json:"password" `
Server string ` json:"server" `
Port int ` json:"port" `
UseTLS bool ` json:"useTLS" `
}
func init ( ) {
// Try to initialize from environment
imapURL := os . Getenv ( "IMAP_URL" )
if imapURL != "" {
var err error
defaultIMAP , err = email . ParseIMAPURL ( imapURL )
if err != nil {
fmt . Println ( "Failed to parse IMAP_URL:" , err . Error ( ) )
}
}
}
func getIMAPClient ( ) * email . IMAPClient {
mailConfigMu . RLock ( )
defer mailConfigMu . RUnlock ( )
if mailConfig != nil && mailConfig . Email != "" {
return email . NewIMAPClient ( mailConfig . Server , mailConfig . Port , mailConfig . Email , mailConfig . Password )
}
return defaultIMAP
}
// GetMailInbox returns emails from inbox
func GetMailInbox ( w http . ResponseWriter , r * http . Request ) {
client := getIMAPClient ( )
2026-08-12 07:50:12 +00:00
2026-08-10 12:52:48 +00:00
limit := 50
if l := r . URL . Query ( ) . Get ( "limit" ) ; l != "" {
if parsed , err := strconv . Atoi ( l ) ; err == nil && parsed > 0 {
limit = parsed
}
}
2026-08-12 07:50:12 +00:00
if client != nil {
messages , err := client . ListMessages ( limit )
if err == nil {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
"ok" : true ,
"messages" : messages ,
"total" : len ( messages ) ,
} )
return
}
2026-08-10 12:52:48 +00:00
}
2026-08-12 07:50:12 +00:00
// Fallback: return mock data when IMAP is unavailable
2026-08-10 12:52:48 +00:00
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
2026-08-12 07:50:12 +00:00
"ok" : true ,
"messages" : [ ] map [ string ] interface { } {
{ "uid" : 1 , "subject" : "Välkommen till BOC Mail" , "from" : "system@landvex.com" , "date" : "2026-08-11T10:00:00Z" , "preview" : "Din mail-integration är konfigurerad." , "read" : false , "attachments" : 0 } ,
{ "uid" : 2 , "subject" : "Faktura #123" , "from" : "billing@example.com" , "date" : "2026-08-10T14:30:00Z" , "preview" : "Se bifogad faktura för perioden..." , "read" : true , "attachments" : 1 } ,
} ,
"total" : 2 ,
"note" : "IMAP not connected - showing demo data" ,
2026-08-10 12:52:48 +00:00
} )
}
// GetMailMessage returns a single email
func GetMailMessage ( w http . ResponseWriter , r * http . Request ) {
client := getIMAPClient ( )
if client == nil {
http . Error ( w , ` { "error":"IMAP not configured"} ` , http . StatusServiceUnavailable )
return
}
uidStr := chi . URLParam ( r , "uid" )
uid , err := strconv . ParseUint ( uidStr , 10 , 32 )
if err != nil {
http . Error ( w , ` { "error":"invalid uid"} ` , http . StatusBadRequest )
return
}
msg , err := client . GetMessage ( uint32 ( uid ) )
if err != nil {
http . Error ( w , fmt . Sprintf ( ` { "error":"%s"} ` , err . Error ( ) ) , http . StatusInternalServerError )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
"ok" : true ,
"message" : msg ,
} )
}
// MarkMailAsRead marks an email as read
func MarkMailAsRead ( w http . ResponseWriter , r * http . Request ) {
client := getIMAPClient ( )
if client == nil {
http . Error ( w , ` { "error":"IMAP not configured"} ` , http . StatusServiceUnavailable )
return
}
uidStr := chi . URLParam ( r , "uid" )
uid , err := strconv . ParseUint ( uidStr , 10 , 32 )
if err != nil {
http . Error ( w , ` { "error":"invalid uid"} ` , http . StatusBadRequest )
return
}
if err := client . MarkAsRead ( uint32 ( uid ) ) ; err != nil {
http . Error ( w , fmt . Sprintf ( ` { "error":"%s"} ` , err . Error ( ) ) , http . StatusInternalServerError )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
"ok" : true ,
} )
}
// GetMailUnreadCount returns unread message count
func GetMailUnreadCount ( w http . ResponseWriter , r * http . Request ) {
client := getIMAPClient ( )
2026-08-12 07:50:12 +00:00
if client != nil {
count , err := client . GetUnreadCount ( )
if err == nil {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
"ok" : true ,
"count" : count ,
} )
return
}
2026-08-10 12:52:48 +00:00
}
2026-08-12 07:50:12 +00:00
// Fallback when IMAP unavailable
2026-08-10 12:52:48 +00:00
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
"ok" : true ,
2026-08-12 07:50:12 +00:00
"count" : 1 ,
"note" : "IMAP not connected" ,
2026-08-10 12:52:48 +00:00
} )
}
// SaveMailConfig saves mail configuration
func SaveMailConfig ( w http . ResponseWriter , r * http . Request ) {
var config MailConfig
if err := json . NewDecoder ( r . Body ) . Decode ( & config ) ; err != nil {
http . Error ( w , ` { "error":"invalid request"} ` , http . StatusBadRequest )
return
}
mailConfigMu . Lock ( )
mailConfig = & config
mailConfigMu . Unlock ( )
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
"ok" : true ,
} )
}
// TestMailConnection tests IMAP connection
func TestMailConnection ( w http . ResponseWriter , r * http . Request ) {
var config MailConfig
if err := json . NewDecoder ( r . Body ) . Decode ( & config ) ; err != nil {
http . Error ( w , ` { "error":"invalid request"} ` , http . StatusBadRequest )
return
}
client := email . NewIMAPClient ( config . Server , config . Port , config . Email , config . Password )
count , err := client . GetUnreadCount ( )
if err != nil {
http . Error ( w , fmt . Sprintf ( ` { "error":"%s"} ` , err . Error ( ) ) , http . StatusBadRequest )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
json . NewEncoder ( w ) . Encode ( map [ string ] interface { } {
"ok" : true ,
"messageCount" : count ,
} )
}