Skip to content

Commit

Permalink
Integration of Gmail API and logging
Browse files Browse the repository at this point in the history
  • Loading branch information
kschroeer committed Jun 13, 2024
1 parent 14422f7 commit f441638
Show file tree
Hide file tree
Showing 45 changed files with 968 additions and 270 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
jdk-22/
res/oauth/*.json
Kilamea.exe
Kilamea.jar
temp.jar
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## 0.2.0 (2024-06-13)

- Bundling the tools for processing file attachments in the new `AttachmentConverter` class
- Enhanced the `createNewMessage()` method in Kilamea.kt with the evaluation of application arguments as file attachments
- Added another MIME type `APPLICATION_OCTET_STREAM`
- Context class extended with the `appDataFolder` property and a way to unset command line arguments
- `HelpAppDataFolderAction` introduced to open the directory with application data directly from the client
- Integrated the Gmail API and encapsulated the calls in the new `GmailClient` class
- Enhanced `MailMapper` with methods for converting Gmail messages
- Automatically encode the sender name to UTF-8 when sending emails
- Extended the `Account` class with a "tokens" property (particularly relevant for Gmail) and the database manager with methods for loading and saving OAuth tokens
- Start of a simple logging mechanism (JUL)
- String extensions implemented
- Changed a few button labels

## 0.1.0 (2024-05-09)

- Start of the project
- UI-Design
- Implementation of the basic functionality
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,22 @@ Of course, anyone not affected can also use the software with pleasure. Everythi
- Reading, writing, replying, and forwarding messages
- Plain text editor
- Easy handling of file attachments
- Passing application arguments as file attachments
- Managing email accounts and folders
- Gmail support
- Address book

## Future goals

- Access to Gmail
- Lazy loading of message content and file attachments
- Integration of rich text editor
- Spellcheck capability
- Implementation of spam filter
- Backup tools

## Technical notes

The application is entirely written in Kotlin (currently version 1.9). For compilation, I use the command line tools. The generated .class files are then packaged into an executable JAR file along with the Kotlin runtime, the resources and the manifest.
I automate this process using Apache Ant. Therefore, modifications to the build.xml might be necessary for your own development environment.

For Windows users, I also offer a way to wrap the executable JAR file into an EXE using Launch4j. I include the OpenJDK (currently version 22) as the VM. The configuration can be found in the launch4j.xml.
24 changes: 15 additions & 9 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
<project name="Kilamea" basedir="." default="all">

<!-- Define properties -->
<property name="kotlin.home" value=""/>
<property environment="env"/>
<property name="kotlin.compile" value="${env.KOTLIN_COMPILE}"/>
<property name="jar.file" value="Kilamea.jar"/>
<property name="temp.file" value="temp.jar"/>
<property name="main.class" value="com.github.kilamea.Launcher"/>
<property name="class.path.entry" value="lib/commons-lang3.jar lib/gson.jar lib/javax.mail.jar lib/liquibase-core.jar lib/org.eclipse.core.commands.jar lib/org.eclipse.equinox.common.jar lib/org.eclipse.jface.jar lib/org.eclipse.osgi.jar lib/sqlite-jdbc.jar lib/swt-win32-win32-x86_64.jar"/>
<property name="class.path.entry" value="lib/commons-lang3.jar lib/google-api-client.jar lib/google-api-services-gmail.jar lib/google-http-client.jar lib/google-http-client-jackson2.jar lib/google-oauth-client.jar lib/google-oauth-client-java6.jar lib/google-oauth-client-jetty.jar lib/gson.jar lib/jackson-core.jar lib/javax.mail.jar lib/javax.servlet.jar lib/jetty.jar lib/jetty-util.jar lib/liquibase-core.jar lib/org.eclipse.core.commands.jar lib/org.eclipse.equinox.common.jar lib/org.eclipse.jface.jar lib/org.eclipse.osgi.jar lib/sqlite-jdbc.jar lib/swt-win32-win32-x86_64.jar"/>

<!-- Define target to replace spaces with semicolons in class path -->
<target name="replaceSpaces">
Expand All @@ -27,20 +28,14 @@

<!-- Define target to compile Kotlin files -->
<target name="compile" depends="replaceSpaces,clean">
<exec executable="${kotlin.home}/bin/kotlinc.bat">
<exec executable="${kotlin.compile}">
<arg value="-cp"/>
<arg value='"${lib.files}"'/>
<arg value="src/com/github/kilamea/Launcher.kt"/>
<arg value="src/com/github/kilamea/core/Bag.kt"/>
<arg value="src/com/github/kilamea/core/Client.kt"/>
<arg value="src/com/github/kilamea/core/Constants.kt"/>
<arg value="src/com/github/kilamea/core/Context.kt"/>
<arg value="src/com/github/kilamea/core/MailMapper.kt"/>
<arg value="src/com/github/kilamea/core/MailProtocol.kt"/>
<arg value="src/com/github/kilamea/core/MimeType.kt"/>
<arg value="src/com/github/kilamea/core/Options.kt"/>
<arg value="src/com/github/kilamea/core/ReceiveException.kt"/>
<arg value="src/com/github/kilamea/core/SendException.kt"/>
<arg value="src/com/github/kilamea/database/DatabaseManager.kt"/>
<arg value="src/com/github/kilamea/database/DBRuntimeException.kt"/>
<arg value="src/com/github/kilamea/entity/AbstractEntity.kt"/>
Expand All @@ -58,6 +53,16 @@
<arg value="src/com/github/kilamea/entity/MessageList.kt"/>
<arg value="src/com/github/kilamea/i18n/I18n.kt"/>
<arg value="src/com/github/kilamea/i18n/Language.kt"/>
<arg value="src/com/github/kilamea/mail/AttachmentConverter.kt"/>
<arg value="src/com/github/kilamea/mail/AuthException.kt"/>
<arg value="src/com/github/kilamea/mail/ClientBuilder.kt"/>
<arg value="src/com/github/kilamea/mail/DefaultClient.kt"/>
<arg value="src/com/github/kilamea/mail/GmailClient.kt"/>
<arg value="src/com/github/kilamea/mail/MailMapper.kt"/>
<arg value="src/com/github/kilamea/mail/MailProtocol.kt"/>
<arg value="src/com/github/kilamea/mail/MimeType.kt"/>
<arg value="src/com/github/kilamea/mail/ReceiveException.kt"/>
<arg value="src/com/github/kilamea/mail/SendException.kt"/>
<arg value="src/com/github/kilamea/sort/ComparatorPool.kt"/>
<arg value="src/com/github/kilamea/sort/FieldComparator.kt"/>
<arg value="src/com/github/kilamea/sort/SortField.kt"/>
Expand All @@ -71,6 +76,7 @@
<arg value="src/com/github/kilamea/swt/TabTraverse.kt"/>
<arg value="src/com/github/kilamea/util/FileUtils.kt"/>
<arg value="src/com/github/kilamea/util/PasswordCrypt.kt"/>
<arg value="src/com/github/kilamea/util/StringExtensions.kt"/>
<arg value="src/com/github/kilamea/util/SystemUtils.kt"/>
<arg value="src/com/github/kilamea/view/AccountDialog.kt"/>
<arg value="src/com/github/kilamea/view/ComposeDialog.kt"/>
Expand Down
13 changes: 12 additions & 1 deletion launch4j.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<headerType>gui</headerType>
<outfile>Kilamea.exe</outfile>
<jar>Kilamea.jar</jar>
<dontWrapJar>false</dontWrapJar>
<dontWrapJar>true</dontWrapJar>
<errTitle>Kilamea</errTitle>
<downloadUrl>http://java.com/download</downloadUrl>
<cmdLine></cmdLine>
Expand All @@ -14,8 +14,19 @@
<classPath>
<mainClass>com.github.kilamea.Launcher</mainClass>
<cp>lib/commons-lang3.jar</cp>
<cp>lib/google-api-client.jar</cp>
<cp>lib/google-api-services-gmail.jar</cp>
<cp>lib/google-http-client.jar</cp>
<cp>lib/google-http-client-jackson2.jar</cp>
<cp>lib/google-oauth-client.jar</cp>
<cp>lib/google-oauth-client-java6.jar</cp>
<cp>lib/google-oauth-client-jetty.jar</cp>
<cp>lib/gson.jar</cp>
<cp>lib/jackson-core.jar</cp>
<cp>lib/javax.mail.jar</cp>
<cp>lib/javax.servlet.jar</cp>
<cp>lib/jetty.jar</cp>
<cp>lib/jetty-util.jar</cp>
<cp>lib/liquibase-core.jar</cp>
<cp>lib/org.eclipse.core.commands.jar</cp>
<cp>lib/org.eclipse.equinox.common.jar</cp>
Expand Down
Binary file added lib/google-api-client.jar
Binary file not shown.
Binary file added lib/google-api-services-gmail.jar
Binary file not shown.
Binary file added lib/google-http-client-jackson2.jar
Binary file not shown.
Binary file added lib/google-http-client.jar
Binary file not shown.
Binary file added lib/google-oauth-client-java6.jar
Binary file not shown.
Binary file added lib/google-oauth-client-jetty.jar
Binary file not shown.
Binary file added lib/google-oauth-client.jar
Binary file not shown.
Binary file added lib/jackson-core.jar
Binary file not shown.
Binary file added lib/javax.servlet.jar
Binary file not shown.
Binary file added lib/jetty-util.jar
Binary file not shown.
Binary file added lib/jetty.jar
Binary file not shown.
13 changes: 10 additions & 3 deletions res/Messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,12 @@ tools_contact_menu=&Adressbuch...
tools_account_menu=&Kontoverwaltung...
tools_prefs_menu=&Einstellungen...
help_menu=&Hilfe
help_about_menu=&Info
help_about_menu=\u00dc&ber Kilamea
help_appdata_folder_menu=Anwendungsdaten-Ordner \u00d6&ffnen

#Various
confirm_delete_account=Sollen die Kontodaten wirklich endg\u00fcltig gel\u00f6scht werden?
confirm_delete_contact=Sollen die Kontaktdaten wirklich endg\u00fcltig gel\u00f6scht werden?
confirm_delete_folder=Soll der Ordner wirklich endg\u00fcltig gel\u00f6scht werden?
confirm_delete_message=Soll die Nachricht wirklich endg\u00fcltig gel\u00f6scht werden?
confirm_empty_trash=Sollen alle Nachrichten wirklich endg\u00fcltig gel\u00f6scht werden?
Expand All @@ -94,8 +97,10 @@ file_chooser_filter_txt=Textdateien (*.txt)
file_chooser_not_found=Die Datei "%s" wurde nicht gefunden.
file_chooser_confirm_overwrite=Die Datei "%s" ist bereits vorhanden. M\u00f6chten Sie sie ersetzen?
save_file_error=Die Datei "%s" konnte nicht gespeichert werden.
show_folder_error=Der Ordner "%s" konnte nicht angezeigt werden.
status_unread=(ungelesen)
status_read=(gelesen)
published_on_github=Der Quellcode ist unter der GPL-Lizenz auf GitHub ver\u00f6ffentlicht:

#Database
database_connect_error=Es konnte keine Verbindung zur Datenbank hergestellt werden. Diese wird zur Verwaltung von Nachrichten, Kontakten und Einstellungen jedoch zwingend ben\u00f6tigt.
Expand All @@ -104,6 +109,7 @@ database_add_or_update_account_error=Fehler beim Speichern der Kontodaten.
database_add_folder_error=Fehler beim Speichern der Ordnerdaten.
database_add_message_error=Fehler beim Speichern der Nachricht.
database_add_attachment_error=Fehler beim Speichern des Dateianhangs.
database_update_account_tokens_error=Fehler beim Speichern des Zugriffstokens.
database_update_folder_name_error=Fehler beim \u00c4ndern des Ordnernamens.
database_update_message_unread_error=Fehler beim \u00c4ndern des Nachrichtenstatus.
database_add_or_update_contact_error=Fehler beim Speichern der Kontaktdaten.
Expand All @@ -120,7 +126,7 @@ database_not_connected_error=Es besteht keine Verbindung zur Datenbank. Diese wi

#Account dialog
account_window_title=Kontoverwaltung
account_done_button=&Fertig
account_done_button=S&chlie\u00dfen
account_new_button=&Neu
account_save_button=&Speichern
account_delete_button=&L\u00f6schen
Expand All @@ -143,6 +149,7 @@ account_no_incoming_port_error=Es wurde kein Posteingangsanschluss eingegeben.
account_no_outgoing_host_error=Es wurde kein Postausgangsserver eingegeben.
account_no_outgoing_port_error=Es wurde kein Postausgangsanschluss eingegeben.
account_exists_error=Ein Konto mit dieser E-Mail-Adresse ist bereits vorhanden.
account_gmail_note=Hinweis: F\u00fcr ein Gmail-Konto m\u00fcssen keine Zugangsdaten und keine Serverinformationen hinterlegt werden. Beim Klicken von "Speichern" erfolgt eine automatische Weiterleitung zu Google, wo der Zugriff selbst freigeschaltet werden muss.

#Compose dialog
compose_window_title=Nachricht
Expand Down Expand Up @@ -172,7 +179,7 @@ compose_date_format=EEEE, d. MMMM yyyy HH:mm:ss Z

#Contact dialog
contact_window_title=Adressbuch
contact_done_button=&Fertig
contact_done_button=S&chlie\u00dfen
contact_new_button=&Neu
contact_save_button=&Speichern
contact_delete_button=&L\u00f6schen
Expand Down
15 changes: 11 additions & 4 deletions res/Messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,12 @@ tools_contact_menu=&Address book...
tools_account_menu=A&ccount management...
tools_prefs_menu=&Preferences...
help_menu=&Help
help_about_menu=&Info
help_about_menu=A&bout Kilamea
help_appdata_folder_menu=&Open application data folder

#Various
confirm_delete_account=Do you really want to permanently delete the account information?
confirm_delete_contact=Do you really want to permanently delete the contact information?
confirm_delete_folder=Do you really want to permanently delete the folder?
confirm_delete_message=Do you really want to permanently delete the message?
confirm_empty_trash=Should all messages really be permanently deleted?
Expand All @@ -94,8 +97,10 @@ file_chooser_filter_txt=Text files (*.txt)
file_chooser_not_found=The file "%s" could not be found.
file_chooser_confirm_overwrite=The file "%s" already exists. Would you like to replace it?
save_file_error=The file "%s" could not be saved.
show_folder_error=The folder "%s" could not be displayed.
status_unread=(unread)
status_read=(read)
published_on_github=The source code is published under the GPL license on GitHub:

#Database
database_connect_error=The database cannot be connected. However, this is absolutely necessary to manage messages, contacts and settings.
Expand All @@ -104,6 +109,7 @@ database_add_or_update_account_error=Error saving account details.
database_add_folder_error=Error saving folder data.
database_add_message_error=Error saving message.
database_add_attachment_error=Error saving file attachment.
database_update_account_tokens_error=Error saving access token.
database_update_folder_name_error=Error changing folder name.
database_update_message_unread_error=Error changing message status.
database_add_or_update_contact_error=Error saving contact details.
Expand All @@ -120,7 +126,7 @@ database_not_connected_error=There is no connection to the database. However, th

#Account dialog
account_window_title=Account management
account_done_button=&Done
account_done_button=&Close
account_new_button=&New
account_save_button=&Save
account_delete_button=De&lete
Expand All @@ -129,7 +135,7 @@ account_name_label=Display na&me:
account_user_label=&Username:
account_password_label=&Password:
account_protocol_label=Incoming server protocol:
account_ssl_active_check=Enable SSL en&cryption
account_ssl_active_check=Enable SSL encr&yption
account_incoming_host_label=Incoming server host:
account_incoming_port_label=Incoming server port:
account_outgoing_host_label=Outgoing server host:
Expand All @@ -143,6 +149,7 @@ account_no_incoming_port_error=No incoming server port specified.
account_no_outgoing_host_error=No outgoing server host specified.
account_no_outgoing_port_error=No outgoing server port specified.
account_exists_error=An account with this email address already exists.
account_gmail_note=Note: For a Gmail account, no login credentials or server information need to be entered. When clicking "Save," there is an automatic redirection to Google, where access must be authorized.

#Compose dialog
compose_window_title=Message
Expand Down Expand Up @@ -172,7 +179,7 @@ compose_date_format=EEEE, d. MMMM yyyy HH:mm:ss Z

#Contact dialog
contact_window_title=Address book
contact_done_button=&Done
contact_done_button=&Close
contact_new_button=&New
contact_save_button=&Save
contact_delete_button=De&lete
Expand Down
18 changes: 18 additions & 0 deletions res/migration/add_tokens_to_accounts.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.0.xsd">

<changeSet id="add_tokens_to_accounts" author="kschroeer">
<addColumn tableName="accounts">
<column name="tokens" type="TEXT">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>

<changeSet id="set_empty_tokens_for_existing_accounts" author="kschroeer">
<sql>UPDATE accounts SET tokens = '' WHERE tokens IS NULL;</sql>
</changeSet>

</databaseChangeLog>
1 change: 1 addition & 0 deletions res/migration/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.0.xsd">

<include file="migration/initial_structure.xml"/>
<include file="migration/add_tokens_to_accounts.xml"/>

</databaseChangeLog>
Empty file added res/oauth/.gitkeep
Empty file.
51 changes: 48 additions & 3 deletions src/com/github/kilamea/Launcher.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,67 @@
package com.github.kilamea

import java.io.File
import java.io.IOException
import java.util.logging.ConsoleHandler
import java.util.logging.FileHandler
import java.util.logging.Level
import java.util.logging.Logger
import java.util.logging.SimpleFormatter

import com.github.kilamea.core.Context
import com.github.kilamea.view.Kilamea

/**
* Main launcher class for the Kilamea application.
* An object containing the main functionality for launching the application.
*
* @since 0.1.0
*/
object Launcher {
private val logger = Logger.getLogger(Launcher::class.java.name)

/**
* Main entry point of the application.
*
* @param args Command-line arguments passed to the application.
* @param args Command line arguments passed to the application.
*/
@JvmStatic
fun main(args: Array<String>) {
val app = Kilamea(Context(args))
val context = Context(args)
try {
initLogging(context.logFile)
} catch (e: IOException) {
System.err.println("Failed to initialize logging: ${e.message}")
e.printStackTrace(System.err)
return
}

logger.info("Starting application...")
val app = Kilamea(context)
app.run()
logger.info("Application has finished running.")
}

/**
* Initializes logging for the application.
*
* @param logFile The file to which log messages should be written.
* @throws IOException If logging cannot be initialized.
*/
@Throws(IOException::class)
private fun initLogging(logFile: File) {
val rootLogger = Logger.getLogger("")
rootLogger.handlers.forEach { rootLogger.removeHandler(it) }

val fileHandler = FileHandler(logFile.toString(), false).apply {
formatter = SimpleFormatter()
}
rootLogger.addHandler(fileHandler)

val consoleHandler = ConsoleHandler().apply {
formatter = SimpleFormatter()
}
rootLogger.addHandler(consoleHandler)

rootLogger.level = Level.INFO
}
}
8 changes: 5 additions & 3 deletions src/com/github/kilamea/core/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ package com.github.kilamea.core
interface Constants {
companion object {
const val APP_NAME: String = "Kilamea"
const val APP_VERSION: String = "0.1.0"
const val APP_VERSION: String = "0.2.0"
const val DATABASE_DRIVER_CLASS: String = "org.sqlite.JDBC"
const val DATABASE_DUMP_FILE: String = "/Dump.sql"
const val DATABASE_FILE_NAME: String = "Kilamea.db"
const val DATABASE_FILE_NAME: String = "$APP_NAME.db"
const val DATABASE_JDBC_SCHEME: String = "jdbc:sqlite:/"
const val GITHUB_REPOSITORY_URL: String = "https://github.com/kschroeer/kilamea"
const val GOOGLE_CREDENTIALS_FILE: String = "/oauth/client_secret.apps.googleusercontent.com.json"
const val LOG_FILE_NAME: String = "$APP_NAME.log"
const val MESSAGE_COUNT: Int = 50
const val TEXT_AREA_COLS: Int = 100
const val TEXT_AREA_ROWS: Int = 20
Expand Down
Loading

0 comments on commit f441638

Please sign in to comment.