diff --git a/lib/api_service.dart b/lib/api_service.dart index 8136798..6c71127 100644 --- a/lib/api_service.dart +++ b/lib/api_service.dart @@ -10,10 +10,13 @@ import 'augment.dart'; import 'dart:html' as html; class ApiService { + static String ip = ""; + static String port = ""; Future> fetchEmailsFromFolder( String folder, int pagenitaion) async { + // print(ip + " " + port); try { - var url = Uri.http('127.0.0.1:3001', 'sorted_threads_by_date', { + var url = Uri.http('$ip:$port', 'sorted_threads_by_date', { 'folder': folder, 'limit': '50', 'offset': pagenitaion.toString(), @@ -49,7 +52,7 @@ class ApiService { List allEmails) async { try { var url = - Uri.http('127.0.0.1:3001', 'get_thread', {'id': threadId.toString()}); + Uri.http('$ip:$port', 'get_thread', {'id': threadId.toString()}); var response = await http.get(url); if (response.statusCode == 200) { @@ -70,15 +73,16 @@ class ApiService { Future> sonicSearch( String list, int limit, int offset, String query) async { try { - var url = Uri.http('127.0.0.1:3001', 'search', { + var url = Uri.http('$ip:$port', 'search_emails', { 'list': list, 'limit': limit.toString(), 'offset': offset.toString(), 'query': query }); + print(url); var response = await http.get(url); - + print(response); if (response.statusCode == 200) { List messagesJson = json.decode(response.body); List messages = @@ -86,6 +90,7 @@ class ApiService { return messages; } + print(response.statusCode); } catch (e) { print("caught $e"); } @@ -99,12 +104,17 @@ class ApiService { try { //attaches email after email from a thread for (var id in IDs) { - var url = Uri.http('127.0.0.1:3001', 'email', {'id': id}); + var url = Uri.http('$ip:$port', 'email', {'id': id}); var response = await http.get(url); if (response.statusCode == 200) { content += response.body; + try { + getAttachmentsInfo("INBOX", id); + } catch (innerError) { + print('_getAttachment info caught error $innerError'); + } content += "
"; } } @@ -121,7 +131,7 @@ class ApiService { Future> fetchFolders() async { try { - var url = Uri.http('127.0.0.1:3001', 'folders'); + var url = Uri.http('$ip:$port', 'folders'); var response = await http.get(url); return List.from(json.decode(response.body)); } catch (e) { @@ -131,7 +141,7 @@ class ApiService { } Future createFolder(String folderName) async { - var url = Uri.http('127.0.0.1:3001', 'create_folder'); + var url = Uri.http('$ip:$port', 'create_folder'); Map requestBody = {'name': folderName}; @@ -154,7 +164,7 @@ class ApiService { } Future deleteFolder(String folderName) async { - var url = Uri.http('127.0.0.1:3001', 'delete_folder'); + var url = Uri.http('$ip:$port', 'delete_folder'); Map requestBody = {'name': folderName}; @@ -175,6 +185,41 @@ class ApiService { print('error making post req: $e'); } } + + Future logIn(String json) async { + // var url = Uri.https('') + // try{ + // String response = await http.post( + // url + // ); + // } + + return false; + } + + Future> getAttachmentsInfo( + String folder, String email_id) async { + try { + var url = Uri.http('127.0.0.1:3001', 'get_attachments_info', + {'folder': folder, 'email_id': email_id}); + print(url); + var response = await http.get(url); + print("response $response"); + if (response.statusCode == 200) { + var result = response.body; + List attachmentList = json.decode(result); + print("attachment list $attachmentList"); + List attachments = + attachmentList.map((al) => AttachmentInfo.fromJson(al)).toList(); + print("attachments $attachments"); + + return attachments; + } + } catch (e) { + print(e); + } + return []; + } } class EmailView extends StatefulWidget { diff --git a/lib/login.dart b/lib/login.dart index 55daed0..c1d8a08 100644 --- a/lib/login.dart +++ b/lib/login.dart @@ -1,24 +1,72 @@ import 'dart:convert'; +import 'package:crab_ui/api_service.dart'; +import 'package:crab_ui/home_page.dart'; import 'package:flutter/material.dart'; +// import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:http/http.dart' as http; +// import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flutter/services.dart' show rootBundle; class AuthService { Future isUserLoggedIn() async { try { - var url = Uri.http('127.0.0.1:3001', 'is_logged_in'); - var response = await http.get(url); + final response = + await http.get(Uri.parse('http://localhost:6823/read-config')); + print(response.statusCode); print(response.body); if (response.statusCode == 200) { - print('all good in the east!'); - List json = jsonDecode(response.body); - print(json[0]); - return true; + final data = jsonDecode(response.body); + // return data['config']; + try { + var url = Uri.http('${data['ip']}:${data['port']}', 'is_logged_in'); + var response = await http.get(url); + print(response.body); + if (response.statusCode == 200) { + print('all good in the east!'); + String jsonOuter = jsonDecode(response.body); + Map json = jsonDecode(jsonOuter); + // print(json["is_logged_in"]); + ApiService.ip = data['ip']; + ApiService.port = data['port']; + return json["is_logged_in"]; + } + } catch (er) { + print(er); + } } } catch (e) { print(e); } return false; } + + Future readConfFile() async { + final content = await rootBundle.loadString('/crabmail.conf'); + return content; + } + + Map parseConfFile(String content) { + final Map config = {}; + final lines = content.split('\n'); + + for (var line in lines) { + line = line.trim(); + if (line.isEmpty || line.startsWith('#')) continue; + + final parts = line.split('='); + if (parts.length == 2) { + final key = parts[0].trim(); + final value = parts[1].trim(); + config[key] = value; + } + } + return config; + } + + Future loginUser(String email, String password) async { + try {} catch (e) {} + return false; + } } class LoginPage extends StatefulWidget { @@ -28,129 +76,327 @@ class LoginPage extends StatefulWidget { _LoginPageState createState() => _LoginPageState(); } +class SplashScreen extends StatefulWidget { + @override + _SplashScreenState createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + final AuthService _authService = AuthService(); + @override + void initState() { + super.initState(); + _checkLoginStatus(); + } + + Future _checkLoginStatus() async { + // SharedPreferences prefs = await SharedPreferences.getInstance(); + // print(prefs); + // bool isLoggedIn = prefs.getBool('isLoggedIn') ?? false; + bool isLoggedIn = await _authService.isUserLoggedIn(); + print("is loogeed in $isLoggedIn"); + if (isLoggedIn) { + Navigator.pushReplacementNamed(context, '/home'); + } else { + Navigator.pushReplacementNamed(context, '/login'); + } + } + + @override + Widget build(BuildContext context) { + return Center( + child: Scaffold( + body: Center(child: CircularProgressIndicator()), + ), + ); + } +} + class _LoginPageState extends State { final AuthService _authService = AuthService(); // Controllers for capturing user input + final TextEditingController _ipController = TextEditingController(); + final TextEditingController _portController = TextEditingController(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); + // final ConfigManager _configManager = + // ConfigManager("${Directory.current.parent}../crabmail2.conf"); // Key to identify the form final _formKey = GlobalKey(); - void checkLogin() async { - // try { - // var url = Uri.http('127.0.0.1:3001', 'is_logged_in'); - // var response = await http.get(url); - // print(response.body); - // if (response.statusCode == 200) { - // print('all good on the west'); - // } - // } catch (e) { - // print(e); - // } - bool isLoggedIn = await _authService.isUserLoggedIn(); - + Future setIp(String ip) async { + // _configManager.setField("api_addr", ip); + return false; } + Future setPort(String port) async { + return false; + } + + Future login() async { + bool result = await _handleLogin(); + if (result) { + Navigator.pushReplacementNamed(context, '/home'); + } + } + // Future _checkConfiguration() async { + // return false; + // } + + // void checkLogin() async { + // try { + // var url = Uri.http('127.0.0.1:3001', 'is_logged_in'); + // var response = await http.get(url); + // print(response.body); + // if (response.statusCode == 200) { + // print('all good on the west'); + // } + // } catch (e) { + // print(e); + // } + // // bool isLoggedIn = await _authService.isUserLoggedIn(); + // } + // Function to handle login action - void _handleLogin() { + Future _handleLogin() async { if (_formKey.currentState!.validate()) { // Perform login action (e.g., authenticate with backend) + String ip = _ipController.text; + String port = _portController.text; String email = _emailController.text; String password = _passwordController.text; // For demonstration, just print the values print('Email: $email'); print('Password: $password'); + print(ip); + print(port); + String baseUrl = "http://$ip:$port"; + print("baseurl " + baseUrl); + print(baseUrl); + try { + final response = + await http.get(Uri.parse('http://localhost:6823/read-config')); + print(response.statusCode); + print(response.body); + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + // return data['config']; + } + } catch (e) { + print("caught in catch"); + print(e); + return false; + } + Map updates = { + // "username": email, + // "password": password, + "ip": ip, + "port": port, + }; + print("past"); + + try { + final sending = await http.post( + Uri.parse('http://localhost:6823/update-config'), + headers: {'Content-Type': "application/json"}, + body: jsonEncode(updates)); + print("sending"); + } catch (e) { + print(e); + return false; + } + try { + // String status = await http.post(Uri.parse('')) + var url_log = Uri.http('$ip:$port', 'log_in'); + Map filteredData = { + "email": email, + "password": password, + // 'email': updates['username'], + // 'password': updates['password'] + }; + print(filteredData); + var status = await http.post( + url_log, + headers: { + 'Content-Type': 'application/json', + }, + body: jsonEncode(filteredData), + ); + if (status.statusCode == 200) { + print('response status ${status.body}'); + if (status.body == "Successful log in") { + ApiService.ip = ip; + ApiService.port = port; + return true; + } + } + } catch (e) { + print(e); + return false; + } + print("after"); + return false; + // final content = await _authService.readConfFile(); + // final config = await _authService.parseConfFile(content); + // print("BASE URL ${config["base_url"]}"); + // print("api address ${config["api_addr"]}"); + // print(config); + // const url = '' // Clear the input fields - _emailController.clear(); - _passwordController.clear(); + // _ipController.clear(); + // _portController.clear(); + // _emailController.clear(); + // _passwordController.clear(); } + return false; } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Login Page'), - ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Form( - key: _formKey, - child: Align( - alignment: Alignment.centerLeft, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Sign in to your email'), - SizedBox( - height: 5, - ), - // Email Field - Container( - width: 200, - child: TextFormField( - controller: _emailController, - decoration: const InputDecoration( - labelText: 'Email', - hintText: 'Enter your email', - helperMaxLines: 1, + // try { + // _configManager.loadConfig(); + // print(_configManager.getField('base_url')); + // } catch (e) { + // print("broke at build $e"); + // } + // _configManager. + return Center( + child: Scaffold( + appBar: AppBar( + title: const Text('Login Page'), + ), + body: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Form( + key: _formKey, + child: Align( + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Sign in to your email'), + SizedBox( + height: 5, ), - validator: (value) { - // Simple email validation - if (value == null || value.isEmpty) { - return 'Please enter your email'; - } - if (!RegExp(r'^\S+@\S+\.\S+$').hasMatch(value)) { - return 'Please enter a valid email address'; - } - return null; - }, - ), - ), - const SizedBox(height: 16.0), - // Password Field - Container( - width: 200, - child: TextFormField( - controller: _passwordController, - decoration: const InputDecoration( - labelText: 'Password', - hintText: 'Enter your password', + Container( + width: 200, + child: TextFormField( + controller: _ipController, + decoration: const InputDecoration( + labelText: "IP", + hintText: 'Enter your IP for the backend', + helperMaxLines: 1, + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your ip'; + } + }, + // onSaved: (value) async { + // final content = await _authService.readConfFile(); + // final config = + // await _authService.parseConfFile(content); + // print("BASE URL ${config["base_url"]}"); + // print("api address ${config["api_addr"]}"); + // //TODO: call a function to set the field ip in conf + // }, + ), ), - obscureText: true, // Hide the password text - validator: (value) { - // Simple password validation - if (value == null || value.isEmpty) { - return 'Please enter your password'; - } - if (value.length < 6) { - return 'Password must be at least 6 characters long'; - } - return null; - }, - ), + Container( + width: 200, + child: TextFormField( + controller: _portController, + decoration: const InputDecoration( + labelText: "Port", + hintText: 'Enter the port', + helperMaxLines: 1, + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your port'; + } + return null; + }, + onSaved: (value) { + //TODO: call a function to set the field port in conf + }, + ), + ), + // Email Field + Container( + width: 200, + child: TextFormField( + controller: _emailController, + decoration: const InputDecoration( + labelText: 'Email', + hintText: 'Enter your email', + helperMaxLines: 1, + ), + validator: (value) { + // Simple email validation + if (value == null || value.isEmpty) { + return 'Please enter your email'; + } + if (!RegExp(r'^\S+@\S+\.\S+$').hasMatch(value)) { + // print(value); + return 'Please enter a valid email address'; + } + return null; + }, + ), + ), + const SizedBox(height: 16.0), + // Password Field + Container( + width: 200, + child: TextFormField( + controller: _passwordController, + decoration: const InputDecoration( + labelText: 'Password', + hintText: 'Enter your password', + ), + obscureText: true, // Hide the password text + autofillHints: null, + validator: (value) { + // Simple password validation + if (value == null || value.isEmpty) { + return 'Please enter your password'; + } + if (value.length < 6) { + return 'Password must be at least 6 characters long'; + } + return null; + }, + ), + ), + const SizedBox(height: 32.0), + // Login Button + SizedBox( + width: 200, + child: ElevatedButton( + onPressed: login, + child: const Text('Login'), + ), + ), + // SizedBox( + // width: 200, + // child: ElevatedButton( + // // onPressed: checkLogin, + // onPressed: () async { + // await _authService.isUserLoggedIn(); + // // print(result); + // }, + // child: const Text('checker'), + // ), + // ) + ], ), - const SizedBox(height: 32.0), - // Login Button - SizedBox( - width: 200, - child: ElevatedButton( - onPressed: _handleLogin, - child: const Text('Login'), - ), - ), - SizedBox( - width: 200, - child: ElevatedButton( - onPressed: checkLogin, - child: const Text('checker'), - ), - ) - ], + ), ), ), ), diff --git a/lib/main.dart b/lib/main.dart index 84b104a..da90a50 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,14 +1,12 @@ import 'package:crab_ui/contact.dart'; import 'package:flutter/material.dart'; import 'home_page.dart'; -// import 'api_service.dart'; import 'login.dart'; -import 'email.dart'; + void main() { WidgetsFlutterBinding.ensureInitialized(); - // debugPaintSizeEnabled = true; - runApp( HyM()); + runApp(HyM()); } class HyM extends StatelessWidget { @@ -22,11 +20,12 @@ class HyM extends StatelessWidget { theme: ThemeData.light(), title: 'HyM', // home: HomeScreen(), - home: HomeScreen(), + initialRoute: "/", routes: { + "/": (context) => SplashScreen(), "/login": (context) => const LoginPage(), - // "/email": (context) => EmailPage(), + "/home": (context) => HomeScreen(), "/contacts": (context) => ContactsPage(), }, ); diff --git a/lib/structs.dart b/lib/structs.dart index 9bc3ecf..6eb1c17 100644 --- a/lib/structs.dart +++ b/lib/structs.dart @@ -21,14 +21,14 @@ class GetThreadResponse { factory GetThreadResponse.fromJson(Map json) { var toList = json['to'] as List; - return GetThreadResponse ( + return GetThreadResponse( id: json['id'], messages: List.from(json['messages']), subject: json['subject'], date: DateTime.parse(json['date']), from_name: json['from_name'], from_address: json['from_address'], - to: toList.map((i)=> MailAddress.fromJson(i)).toList(), + to: toList.map((i) => MailAddress.fromJson(i)).toList(), ); } } @@ -51,6 +51,7 @@ class MailAddress { return '${name} <${address}>'; } } + // //old data structure class SerializableMessage { final String name; @@ -100,4 +101,20 @@ class SerializableMessage { in_reply_to: json['in_reply_to'], ); } -} \ No newline at end of file +} + +class AttachmentInfo { + final String name; + final int size; + final String path; + + AttachmentInfo({required this.name, required this.size, required this.path}); + + factory AttachmentInfo.fromJson(Map json) { + return AttachmentInfo( + name: json['name'], + size: json['size'], + path: json['path'], + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index a985a82..de4abb5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,10 @@ dependencies: http: 1.2.2 flutter_html_all: 3.0.0-beta.2 flutter_widget_from_html: ^0.10.0 - + shared_preferences: ^2.0.6 + encrypt: ^5.0.0 + pointycastle: ^3.4.0 + mime: ^1.0.3 english_words: ^4.0.0 provider: ^6.0.0