1
0
mirror of https://github.com/fabianonline/telegram_backup.git synced 2024-11-22 16:56:16 +00:00

WIP: Lots and lots of rewriting.

This commit is contained in:
Fabian Schlenz 2018-03-16 06:59:18 +01:00
parent 2d409352bc
commit eea08a5559
19 changed files with 713 additions and 997 deletions

View File

@ -22,120 +22,64 @@ import com.github.badoualy.telegram.mtproto.auth.AuthKey
import com.github.badoualy.telegram.mtproto.model.MTSession import com.github.badoualy.telegram.mtproto.model.MTSession
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
import org.slf4j.LoggerFactory
import org.slf4j.Logger
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.IOException import java.io.IOException
internal class ApiStorage(prefix: String?) : TelegramApiStorage { internal class ApiStorage(val base_dir: String) : TelegramApiStorage {
private var prefix: String? = null var auth_key: AuthKey? = null
private var do_save = false var dc: DataCenter? = null
private var auth_key: AuthKey? = null val file_auth_key: File
private var dc: DataCenter? = null val file_dc: File
private var file_auth_key: File? = null val logger = LoggerFactory.getLogger(ApiStorage::class.java)
private var file_dc: File? = null
init { init {
this.setPrefix(prefix) file_auth_key = File(base_dir + Config.FILE_NAME_AUTH_KEY)
} file_dc = File(base_dir + Config.FILE_NAME_DC)
fun setPrefix(prefix: String?) {
this.prefix = prefix
this.do_save = this.prefix != null
if (this.do_save) {
val base = Config.FILE_BASE +
File.separatorChar +
this.prefix +
File.separatorChar
this.file_auth_key = File(base + Config.FILE_NAME_AUTH_KEY)
this.file_dc = File(base + Config.FILE_NAME_DC)
this._saveAuthKey()
this._saveDc()
} else {
this.file_auth_key = null
this.file_dc = null
}
} }
override fun saveAuthKey(authKey: AuthKey) { override fun saveAuthKey(authKey: AuthKey) {
this.auth_key = authKey FileUtils.writeByteArrayToFile(file_auth_key, authKey.key)
this._saveAuthKey()
}
private fun _saveAuthKey() {
if (this.do_save && this.auth_key != null) {
try {
FileUtils.writeByteArrayToFile(this.file_auth_key, this.auth_key!!.key)
} catch (e: IOException) {
e.printStackTrace()
}
}
} }
override fun loadAuthKey(): AuthKey? { override fun loadAuthKey(): AuthKey? {
if (this.auth_key != null) return this.auth_key
if (this.file_auth_key != null) {
try { try {
return AuthKey(FileUtils.readFileToByteArray(this.file_auth_key)) return AuthKey(FileUtils.readFileToByteArray(file_auth_key))
} catch (e: IOException) { } catch (e: FileNotFoundException) {
if (e !is FileNotFoundException) e.printStackTrace()
}
}
return null return null
} }
}
override fun saveDc(dataCenter: DataCenter) { override fun saveDc(dataCenter: DataCenter) {
this.dc = dataCenter FileUtils.write(file_dc, dataCenter.toString())
this._saveDc()
}
private fun _saveDc() {
if (this.do_save && this.dc != null) {
try {
FileUtils.write(this.file_dc, this.dc!!.toString())
} catch (e: IOException) {
e.printStackTrace()
}
}
} }
override fun loadDc(): DataCenter? { override fun loadDc(): DataCenter? {
if (this.dc != null) return this.dc
if (this.file_dc != null) {
try { try {
val infos = FileUtils.readFileToString(this.file_dc).split(":") val infos = FileUtils.readFileToString(this.file_dc).split(":")
return DataCenter(infos[0], Integer.parseInt(infos[1])) return DataCenter(infos[0], Integer.parseInt(infos[1]))
} catch (e: IOException) { } catch (e: FileNotFoundException) {
if (e !is FileNotFoundException) e.printStackTrace()
}
}
return null return null
} }
}
override fun deleteAuthKey() { override fun deleteAuthKey() {
if (this.do_save) {
try { try {
FileUtils.forceDelete(this.file_auth_key) FileUtils.forceDelete(file_auth_key)
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() logger.warn("Exception in deleteAuthKey(): {}", e)
}
} }
} }
override fun deleteDc() { override fun deleteDc() {
if (this.do_save) {
try { try {
FileUtils.forceDelete(this.file_dc) FileUtils.forceDelete(file_dc)
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() logger.warn("Exception in deleteDc(): {}", e)
}
} }
} }

View File

@ -29,149 +29,136 @@ import java.util.HashMap
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.slf4j.Logger import org.slf4j.Logger
class CommandLineController { class CommandLineController(val options: CommandLineOptions) {
private val storage: ApiStorage init {
val storage: ApiStorage
val app: TelegramApp val app: TelegramApp
val target_dir: String val target_dir: String
val file_base: String val file_base: String
val phone_number: String val phone_number: String
val account_file_base: String val handler: TelegramUpdateHandler
val client: TelegramClient
private fun getLine(): String { val user_manager: UserManager
if (System.console() != null) { val inisettings: IniSettings
return System.console().readLine("> ") val database: Database
} else {
print("> ")
return Scanner(System.`in`).nextLine()
}
}
private fun getPassword(): String {
if (System.console() != null) {
return String(System.console().readPassword("> "))
} else {
return getLine()
}
}
init {
logger.info("CommandLineController started. App version {}", Config.APP_APPVER) logger.info("CommandLineController started. App version {}", Config.APP_APPVER)
printHeader() printHeader()
if (CommandLineOptions.cmd_version) { if (options.cmd_version) {
System.exit(0) System.exit(0)
} else if (CommandLineOptions.cmd_help) { } else if (options.cmd_help) {
show_help() show_help()
System.exit(0) System.exit(0)
} else if (CommandLineOptions.cmd_license) { } else if (options.cmd_license) {
show_license() show_license()
System.exit(0) System.exit(0)
} }
// Setup TelegramApp
logger.debug("Initializing TelegramApp")
app = TelegramApp(Config.APP_ID, Config.APP_HASH, Config.APP_MODEL, Config.APP_SYSVER, Config.APP_APPVER, Config.APP_LANG)
// Setup file_base // Setup file_base
logger.debug("Target dir from Config: {}", Config.TARGET_DIR.anonymize()) logger.debug("Target dir from Config: {}", Config.TARGET_DIR.anonymize())
target_dir = CommandLineOptions.val_target ?: Config.TARGET_DIR target_dir = options.val_target ?: Config.TARGET_DIR
logger.debug("Target dir after options: {}", target_dir) logger.debug("Target dir after options: {}", target_dir)
println("Base directory for files: ${target_dir.anonymize()}") println("Base directory for files: ${target_dir.anonymize()}")
if (CommandLineOptions.cmd_list_accounts) { if (options.cmd_list_accounts) {
Utils.print_accounts(target_dir) Utils.print_accounts(target_dir)
System.exit(0) System.exit(0)
} }
if (CommandLineOptions.cmd_login) { if (options.cmd_login) {
cmd_login(target_dir, CommandLineOptions.val_account) cmd_login(app, target_dir, options.val_account)
} }
logger.trace("Checking accounts") logger.trace("Checking accounts")
try { phone_number = try { selectAccount(target_dir, options.val_account)
phone_number = selectAccount(target_dir, CommandLineOptions.val_account)
} catch(e: AccountNotFoundException) { } catch(e: AccountNotFoundException) {
show_error("The specified account could not be found.") show_error("The specified account could not be found.")
} catch(e: NoAccountsException) { } catch(e: NoAccountsException) {
println("No accounts found. Starting login process...") println("No accounts found. Starting login process...")
cmd_login(target_dir, CommandLineOptions.val_account) cmd_login(app, target_dir, options.val_account)
} }
file_base = target_dir + File.separatorChar + account_to_use // TODO: Create a new TelegramApp if the user set his/her own TelegramApp credentials
account = Account(file_base, account_to_use) // At this point we can assume that the selected user account ("phone_number") exists.
// So we can create some objects:
file_base = build_file_base(target_dir, phone_number)
logger.debug("Initializing TelegramApp")
app = TelegramApp(Config.APP_ID, Config.APP_HASH, Config.APP_MODEL, Config.APP_SYSVER, Config.APP_APPVER, Config.APP_LANG)
logger.debug("CommandLineOptions.cmd_login: {}", CommandLineOptions.cmd_login)
logger.info("Initializing ApiStorage") logger.info("Initializing ApiStorage")
storage = ApiStorage(account) storage = ApiStorage(file_base)
logger.info("Initializing TelegramUpdateHandler") logger.info("Initializing TelegramUpdateHandler")
val handler = TelegramUpdateHandler() handler = TelegramUpdateHandler()
logger.info("Creating Client") logger.info("Creating Client")
val client = Kotlogram.getDefaultClient(app, storage, Kotlogram.PROD_DC4, handler) client = Kotlogram.getDefaultClient(app, storage, Kotlogram.PROD_DC4, handler)
// From now on we have a new catch-all-block that will terminate it's TelegramClient when an exception happens.
try { try {
logger.info("Initializing UserManager") logger.info("Initializing UserManager")
UserManager.init(client) user_manager = UserManager(client)
val user = UserManager.getInstance()
if (!CommandLineOptions.cmd_login && !user.loggedIn) { // TODO
/*if (!options.cmd_login && !user.loggedIn) {
println("Your authorization data is invalid or missing. You will have to login with Telegram again.") println("Your authorization data is invalid or missing. You will have to login with Telegram again.")
CommandLineOptions.cmd_login = true options.cmd_login = true
} }*/
if (account != null && user.loggedIn) {
if (account != "+" + user.user!!.getPhone()) { if (phone_number != user_manager.phone) {
logger.error("Account: {}, user.user!!.getPhone(): +{}", account.anonymize(), user.user!!.getPhone().anonymize()) logger.error("phone_number: {}, user_manager.phone: {}", phone_number.anonymize(), user_manager.phone.anonymize())
throw RuntimeException("Account / User mismatch") show_error("Account / User mismatch")
}
} }
// Load the ini file. // Load the ini file.
IniSettings.load() inisettings = IniSettings(file_base)
logger.debug("CommandLineOptions.cmd_login: {}", CommandLineOptions.cmd_login)
if (CommandLineOptions.cmd_login) {
cmd_login(CommandLineOptions.val_account)
System.exit(0)
}
// If we reach this point, we can assume that there is an account and a database can be loaded / created. // If we reach this point, we can assume that there is an account and a database can be loaded / created.
Database.init(client) database = Database(file_base, user_manager)
if (CommandLineOptions.cmd_stats) {
cmd_stats() if (options.cmd_stats) {
cmd_stats(file_base, database)
System.exit(0) System.exit(0)
} }
if (CommandLineOptions.val_test != null) {
if (CommandLineOptions.val_test == 1) { if (options.val_test != null) {
if (options.val_test == 1) {
TestFeatures.test1() TestFeatures.test1()
} else if (CommandLineOptions.val_test == 2) { } else if (options.val_test == 2) {
TestFeatures.test2() TestFeatures.test2()
} else { } else {
System.out.println("Unknown test " + CommandLineOptions.val_test) System.out.println("Unknown test " + options.val_test)
} }
System.exit(1) System.exit(1)
} }
logger.debug("CommandLineOptions.val_export: {}", CommandLineOptions.val_export)
if (CommandLineOptions.val_export != null) { val export = options.val_export
if (CommandLineOptions.val_export!!.toLowerCase().equals("html")) { logger.debug("options.val_export: {}", export)
(HTMLExporter()).export() if (export != null) {
if (export.toLowerCase().equals("html")) {
HTMLExporter().export()
System.exit(0) System.exit(0)
} else { } else {
show_error("Unknown export format.") show_error("Unknown export format '${export}'.")
} }
} }
if (user.loggedIn) {
System.out.println("You are logged in as ${user.userString.anonymize()}")
} else {
println("You are not logged in.")
System.exit(1)
}
logger.info("Initializing Download Manager")
val d = DownloadManager(client, CommandLineDownloadProgress())
if (CommandLineOptions.cmd_list_channels) { println("You are logged in as ${user_manager.toString().anonymize()}")
logger.info("Initializing Download Manager")
val d = DownloadManager(client, CommandLineDownloadProgress(), database, user_manager, inisettings)
if (options.cmd_list_channels) {
val chats = d.getChats() val chats = d.getChats()
val print_header = {download: Boolean -> println("%-15s %-40s %s".format("ID", "Title", if (download) "Download" else "")); println("-".repeat(65)) } val print_header = {download: Boolean -> println("%-15s %-40s %s".format("ID", "Title", if (download) "Download" else "")); println("-".repeat(65)) }
val format = {c: DownloadManager.Channel, download: Boolean -> "%-15s %-40s %s".format(c.id.toString().anonymize(), c.title.anonymize(), if (download) (if(c.download) "YES" else "no") else "")} val format = {c: DownloadManager.Channel, download: Boolean -> "%-15s %-40s %s".format(c.id.toString().anonymize(), c.title.anonymize(), if (download) (if(c.download) "YES" else "no") else "")}
var download: Boolean var download: Boolean
println("Channels:") println("Channels:")
download = IniSettings.download_channels download = inisettings.download_channels
if (!download) println("Download of channels is disabled - see download_channels in config.ini") if (!download) println("Download of channels is disabled - see download_channels in config.ini")
print_header(download) print_header(download)
for (c in chats.channels) { for (c in chats.channels) {
@ -179,7 +166,7 @@ class CommandLineController {
} }
println() println()
println("Supergroups:") println("Supergroups:")
download = IniSettings.download_supergroups download = inisettings.download_supergroups
if (!download) println("Download of supergroups is disabled - see download_supergroups in config.ini") if (!download) println("Download of supergroups is disabled - see download_supergroups in config.ini")
print_header(download) print_header(download)
for (c in chats.supergroups) { for (c in chats.supergroups) {
@ -188,10 +175,10 @@ class CommandLineController {
System.exit(0) System.exit(0)
} }
logger.debug("Calling DownloadManager.downloadMessages with limit {}", CommandLineOptions.val_limit_messages) logger.debug("Calling DownloadManager.downloadMessages with limit {}", options.val_limit_messages)
d.downloadMessages(CommandLineOptions.val_limit_messages) d.downloadMessages(options.val_limit_messages)
logger.debug("IniSettings.download_media: {}", IniSettings.download_media) logger.debug("IniSettings#download_media: {}", inisettings.download_media)
if (IniSettings.download_media) { if (inisettings.download_media) {
logger.debug("Calling DownloadManager.downloadMedia") logger.debug("Calling DownloadManager.downloadMedia")
d.downloadMedia() d.downloadMedia()
} else { } else {
@ -202,9 +189,9 @@ class CommandLineController {
e.printStackTrace() e.printStackTrace()
logger.error("Exception caught!", e) logger.error("Exception caught!", e)
// If we encountered an exception, we definitely don't want to start the daemon mode now. // If we encountered an exception, we definitely don't want to start the daemon mode now.
CommandLineOptions.cmd_daemon = false options.cmd_daemon = false
} finally { } finally {
if (CommandLineOptions.cmd_daemon) { if (options.cmd_daemon) {
handler.activate() handler.activate()
println("DAEMON mode requested - keeping running.") println("DAEMON mode requested - keeping running.")
} else { } else {
@ -225,79 +212,63 @@ class CommandLineController {
} }
private fun selectAccount(file_base: String, requested_account: String?): String { private fun selectAccount(file_base: String, requested_account: String?): String {
val found_account: String? var found_account: String? = null
val accounts = Utils.getAccounts(file_base) val accounts = Utils.getAccounts(file_base)
if (requested_account != null) { if (requested_account != null) {
logger.debug("Account requested: {}", requested_account.anonymize()) logger.debug("Account requested: {}", requested_account.anonymize())
logger.trace("Checking accounts for match.") logger.trace("Checking accounts for match.")
found_account = accounts.find{it == requested_account} found_account = accounts.find{it == requested_account}
if (found_account == null) {
throw AccountNotFoundException()
}
} else if (accounts.size == 0) { } else if (accounts.size == 0) {
throw NoAccountsException() throw NoAccountsException()
} else if (accounts.size == 1) { } else if (accounts.size == 1) {
found_account = accounts.firstElement() found_account = accounts.firstElement()
println("Using only available account: " + account.anonymize()) println("Using only available account: " + found_account.anonymize())
} else { } else {
show_error(("You didn't specify which account to use.\n" + show_error(("You have more than one account but didn't specify which one to use.\n" +
"Use '--account <x>' to use account <x>.\n" + "Use '--account <x>' to use account <x>.\n" +
"Use '--list-accounts' to see all available accounts.")) "Use '--list-accounts' to see all available accounts."))
System.exit(1) System.exit(1)
} }
logger.debug("accounts.size: {}", accounts.size)
logger.debug("account: {}", found_account.anonymize()) if (found_account == null) {
return found_account!! throw AccountNotFoundException()
} }
private fun cmd_stats() { logger.debug("accounts.size: {}", accounts.size)
logger.debug("account: {}", found_account.anonymize())
return found_account
}
private fun cmd_stats(file_base: String, db: Database) {
println() println()
println("Stats:") println("Stats:")
val format = "%40s: %d%n" val format = "%40s: %d%n"
System.out.format(format, "Number of accounts", Utils.getAccounts().size) System.out.format(format, "Number of accounts", Utils.getAccounts(file_base).size)
System.out.format(format, "Number of messages", Database.getInstance().getMessageCount()) System.out.format(format, "Number of messages", db.getMessageCount())
System.out.format(format, "Number of chats", Database.getInstance().getChatCount()) System.out.format(format, "Number of chats", db.getChatCount())
System.out.format(format, "Number of users", Database.getInstance().getUserCount()) System.out.format(format, "Number of users", db.getUserCount())
System.out.format(format, "Top message ID", Database.getInstance().getTopMessageID()) System.out.format(format, "Top message ID", db.getTopMessageID())
println() println()
println("Media Types:") println("Media Types:")
for ((key, value) in Database.getInstance().getMessageMediaTypesWithCount()) { for ((key, value) in db.getMessageMediaTypesWithCount()) {
System.out.format(format, key, value) System.out.format(format, key, value)
} }
println() println()
println("Api layers of messages:") println("Api layers of messages:")
for ((key, value) in Database.getInstance().getMessageApiLayerWithCount()) { for ((key, value) in db.getMessageApiLayerWithCount()) {
System.out.format(format, key, value) System.out.format(format, key, value)
} }
println() println()
println("Message source types:") println("Message source types:")
for ((key, value) in Database.getInstance().getMessageSourceTypeWithCount()) { for ((key, value) in db.getMessageSourceTypeWithCount()) {
System.out.format(format, key, value) System.out.format(format, key, value)
} }
} }
private fun cmd_login(target_dir: String, phoneToUse: String?): Nothing { private fun cmd_login(app: TelegramApp, target_dir: String, phoneToUse: String?): Nothing {
val phone: String LoginManager(app, target_dir, phoneToUse).run()
if (phoneToUse == null) { System.exit(0)
println("Please enter your phone number in international format.") throw RuntimeException("Code never reaches this. This exists just to keep the Kotlin compiler happy.")
println("Example: +4917077651234")
phone = getLine()
} else {
phone = phoneToUse
}
user.sendCodeToPhoneNumber(phone)
println("Telegram sent you a code. Please enter it here.")
val code = getLine()
user.verifyCode(code)
if (user.isPasswordNeeded) {
println("We also need your account password. Please enter it now. It should not be printed, so it's okay if you see nothing while typing it.")
val pw = getPassword()
user.verifyPassword(pw)
}
storage.setPrefix("+" + user.user!!.getPhone())
System.out.println("Everything seems fine. Please run this tool again with '--account +" + user.user!!.getPhone().anonymize() + " to use this account.")
} }
private fun show_help() { private fun show_help() {
@ -323,15 +294,18 @@ class CommandLineController {
companion object { companion object {
private val logger = LoggerFactory.getLogger(CommandLineController::class.java) private val logger = LoggerFactory.getLogger(CommandLineController::class.java)
public fun show_error(error: String) { public fun show_error(error: String): Nothing {
logger.error(error) logger.error(error)
println("ERROR: " + error) println("ERROR: " + error)
System.exit(1) System.exit(1)
throw RuntimeException("Code never reaches this. This exists just to keep the Kotlin compiler happy.")
} }
fun show_license() { fun show_license() {
println("TODO: Print the GPL.") println("TODO: Print the GPL.")
} }
fun build_file_base(target_dir: String, account_to_use: String) = target_dir + File.separatorChar + account_to_use + File.separatorChar
} }
class AccountNotFoundException() : Exception("Account not found") {} class AccountNotFoundException() : Exception("Account not found") {}

View File

@ -15,10 +15,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
package de.fabianonline.telegram_backup package de.fabianonline.telegram_backup
internal object CommandLineOptions { class CommandLineOptions(args: Array<String>) {
public var cmd_console = false var cmd_console = false
public var cmd_help = false var cmd_help = false
public var cmd_login = false var cmd_login = false
var cmd_debug = false var cmd_debug = false
var cmd_trace = false var cmd_trace = false
var cmd_trace_telegram = false var cmd_trace_telegram = false
@ -34,8 +34,8 @@ internal object CommandLineOptions {
var val_target: String? = null var val_target: String? = null
var val_export: String? = null var val_export: String? = null
var val_test: Int? = null var val_test: Int? = null
@JvmStatic
fun parseOptions(args: Array<String>) { init {
var last_cmd: String? = null var last_cmd: String? = null
loop@ for (arg in args) { loop@ for (arg in args) {
if (last_cmd != null) { if (last_cmd != null) {

View File

@ -29,24 +29,30 @@ import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.classic.Level import ch.qos.logback.classic.Level
fun main(args: Array<String>) { fun main(args: Array<String>) {
CommandLineOptions.parseOptions(args) val clr = CommandLineRunner(args)
CommandLineRunner.setupLogging() clr.setupLogging()
CommandLineRunner.checkVersion() clr.checkVersion()
clr.run()
if (true || CommandLineOptions.cmd_console) {
// Always use the console for now.
CommandLineController()
} else {
GUIController()
}
} }
object CommandLineRunner { class CommandLineRunner(args: Array<String>) {
fun setupLogging() {
val logger = LoggerFactory.getLogger(CommandLineRunner::class.java) as Logger val logger = LoggerFactory.getLogger(CommandLineRunner::class.java) as Logger
val options = CommandLineOptions(args)
fun run() {
// Always use the console for now.
try {
CommandLineController(options)
} catch (e: Throwable) {
println("An error occured!")
e.printStackTrace()
logger.error("Exception caught!", e)
System.exit(1)
}
}
fun setupLogging() {
logger.trace("Setting up Loggers...") logger.trace("Setting up Loggers...")
val rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as Logger val rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as Logger
val rootContext = rootLogger.getLoggerContext() val rootContext = rootLogger.getLoggerContext()
@ -65,13 +71,13 @@ object CommandLineRunner {
rootLogger.addAppender(appender) rootLogger.addAppender(appender)
rootLogger.setLevel(Level.OFF) rootLogger.setLevel(Level.OFF)
if (CommandLineOptions.cmd_trace) { if (options.cmd_trace) {
(LoggerFactory.getLogger("de.fabianonline.telegram_backup") as Logger).setLevel(Level.TRACE) (LoggerFactory.getLogger("de.fabianonline.telegram_backup") as Logger).setLevel(Level.TRACE)
} else if (CommandLineOptions.cmd_debug) { } else if (options.cmd_debug) {
(LoggerFactory.getLogger("de.fabianonline.telegram_backup") as Logger).setLevel(Level.DEBUG) (LoggerFactory.getLogger("de.fabianonline.telegram_backup") as Logger).setLevel(Level.DEBUG)
} }
if (CommandLineOptions.cmd_trace_telegram) { if (options.cmd_trace_telegram) {
(LoggerFactory.getLogger("com.github.badoualy") as Logger).setLevel(Level.TRACE) (LoggerFactory.getLogger("com.github.badoualy") as Logger).setLevel(Level.TRACE)
} }
} }

View File

@ -21,7 +21,6 @@ import com.github.badoualy.telegram.tl.core.TLVector
import com.github.badoualy.telegram.api.TelegramClient import com.github.badoualy.telegram.api.TelegramClient
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.slf4j.Logger import org.slf4j.Logger
import java.sql.Connection import java.sql.Connection
import java.sql.DriverManager import java.sql.DriverManager
import java.sql.Statement import java.sql.Statement
@ -47,60 +46,45 @@ import java.text.SimpleDateFormat
import de.fabianonline.telegram_backup.mediafilemanager.AbstractMediaFileManager import de.fabianonline.telegram_backup.mediafilemanager.AbstractMediaFileManager
import de.fabianonline.telegram_backup.mediafilemanager.FileManagerFactory import de.fabianonline.telegram_backup.mediafilemanager.FileManagerFactory
class Database private constructor(var client: TelegramClient) { class Database constructor(val file_base: String, val user_manager: UserManager) {
private var conn: Connection? = null val conn: Connection
private var stmt: Statement? = null val stmt: Statement
var user_manager: UserManager val logger = LoggerFactory.getLogger(Database::class.java)
init { init {
private val logger = LoggerFactory.getLogger(Database::class.java) println("Opening database...")
this.user_manager = UserManager.getInstance()
System.out.println("Opening database...")
try { try {
Class.forName("org.sqlite.JDBC") Class.forName("org.sqlite.JDBC")
} catch (e: ClassNotFoundException) { } catch (e: ClassNotFoundException) {
CommandLineController.show_error("Could not load jdbc-sqlite class.") throw RuntimeException("Could not load jdbc-sqlite class.")
} }
val path = "jdbc:sqlite:${user_manager.fileBase}${Config.FILE_NAME_DB}" val path = "jdbc:sqlite:${file_base}${Config.FILE_NAME_DB}"
try { try {
conn = DriverManager.getConnection(path) conn = DriverManager.getConnection(path)!!
stmt = conn!!.createStatement() stmt = conn.createStatement()
} catch (e: SQLException) { } catch (e: SQLException) {
CommandLineController.show_error("Could not connect to SQLITE database.") throw RuntimeException("Could not connect to SQLITE database.")
} }
// Run updates // Run updates
val updates = DatabaseUpdates(conn!!, this) val updates = DatabaseUpdates(conn!!, this)
updates.doUpdates() updates.doUpdates()
System.out.println("Database is ready.") println("Database is ready.")
}
fun getTopMessageID(): Int {
try {
val rs = stmt!!.executeQuery("SELECT MAX(message_id) FROM messages WHERE source_type IN ('group', 'dialog')")
rs.next()
val result = rs.getInt(1)
rs.close()
return result
} catch (e: SQLException) {
return 0
}
} }
fun getTopMessageID(): Int = queryInt("SELECT MAX(message_id) FROM messages WHERE source_type IN ('group', 'dialog')")
fun getMessageCount(): Int = queryInt("SELECT COUNT(*) FROM messages") fun getMessageCount(): Int = queryInt("SELECT COUNT(*) FROM messages")
fun getChatCount(): Int = queryInt("SELECT COUNT(*) FROM chats") fun getChatCount(): Int = queryInt("SELECT COUNT(*) FROM chats")
fun getUserCount(): Int = queryInt("SELECT COUNT(*) FROM users") fun getUserCount(): Int = queryInt("SELECT COUNT(*) FROM users")
fun getMissingIDs: LinkedList<Int>() fun getMissingIDs(): LinkedList<Int> {
try { try {
val missing = LinkedList<Int>() val missing = LinkedList<Int>()
val max = getTopMessageID() val max = getTopMessageID()
val rs = stmt!!.executeQuery("SELECT message_id FROM messages WHERE source_type IN ('group', 'dialog') ORDER BY id") val rs = stmt.executeQuery("SELECT message_id FROM messages WHERE source_type IN ('group', 'dialog') ORDER BY id")
rs.next() rs.next()
var id = rs.getInt(1) var id = rs.getInt(1)
for (i in 1..max) { for (i in 1..max) {
@ -126,7 +110,7 @@ class Database private constructor(var client: TelegramClient) {
fun getMessagesWithMedia(): LinkedList<TLMessage?> { fun getMessagesWithMedia(): LinkedList<TLMessage?> {
try { try {
val list = LinkedList<TLMessage?>() val list = LinkedList<TLMessage?>()
val rs = stmt!!.executeQuery("SELECT data FROM messages WHERE has_media=1") val rs = stmt.executeQuery("SELECT data FROM messages WHERE has_media=1")
while (rs.next()) { while (rs.next()) {
list.add(bytesToTLMessage(rs.getBytes(1))) list.add(bytesToTLMessage(rs.getBytes(1)))
} }
@ -139,7 +123,7 @@ class Database private constructor(var client: TelegramClient) {
} }
fun getMessagesFromUserCount() = queryInt("SELECT COUNT(*) FROM messages WHERE sender_id=" + user_manager.user!!.getId()) fun getMessagesFromUserCount() = queryInt("SELECT COUNT(*) FROM messages WHERE sender_id=" + user_manager.id)
fun getMessageTypesWithCount(): HashMap<String, Int> = getMessageTypesWithCount(GlobalChat()) fun getMessageTypesWithCount(): HashMap<String, Int> = getMessageTypesWithCount(GlobalChat())
@ -148,7 +132,7 @@ class Database private constructor(var client: TelegramClient) {
fun getMessageSourceTypeWithCount(): HashMap<String, Int> { fun getMessageSourceTypeWithCount(): HashMap<String, Int> {
val map = HashMap<String, Int>() val map = HashMap<String, Int>()
try { try {
val rs = stmt!!.executeQuery("SELECT COUNT(id), source_type FROM messages GROUP BY source_type ORDER BY source_type") val rs = stmt.executeQuery("SELECT COUNT(id), source_type FROM messages GROUP BY source_type ORDER BY source_type")
while (rs.next()) { while (rs.next()) {
val source_type = rs.getString(2) ?: "null" val source_type = rs.getString(2) ?: "null"
map.put("count.messages.source_type.${source_type}", rs.getInt(1)) map.put("count.messages.source_type.${source_type}", rs.getInt(1))
@ -163,7 +147,7 @@ class Database private constructor(var client: TelegramClient) {
fun getMessageApiLayerWithCount(): HashMap<String, Int> { fun getMessageApiLayerWithCount(): HashMap<String, Int> {
val map = HashMap<String, Int>() val map = HashMap<String, Int>()
try { try {
val rs = stmt!!.executeQuery("SELECT COUNT(id), api_layer FROM messages GROUP BY api_layer ORDER BY api_layer") val rs = stmt.executeQuery("SELECT COUNT(id), api_layer FROM messages GROUP BY api_layer ORDER BY api_layer")
while (rs.next()) { while (rs.next()) {
var layer = rs.getInt(2) var layer = rs.getInt(2)
map.put("count.messages.api_layer.$layer", rs.getInt(1)) map.put("count.messages.api_layer.$layer", rs.getInt(1))
@ -179,25 +163,12 @@ class Database private constructor(var client: TelegramClient) {
fun getMessageTimesMatrix(): Array<IntArray> = getMessageTimesMatrix(GlobalChat()) fun getMessageTimesMatrix(): Array<IntArray> = getMessageTimesMatrix(GlobalChat())
fun getEncoding(): String { fun getEncoding(): String = queryString("PRAGMA encoding")
try {
val rs = stmt!!.executeQuery("PRAGMA encoding")
rs.next()
val result = rs.getString(1)
rs.close()
return result
} catch (e: SQLException) {
logger.debug("SQLException: {}", e)
return "unknown"
}
}
fun getListOfChatsForExport(): LinkedList<Chat> { fun getListOfChatsForExport(): LinkedList<Chat> {
val list = LinkedList<Chat>() val list = LinkedList<Chat>()
try {
val rs = stmt!!.executeQuery("SELECT chats.id, chats.name, COUNT(messages.id) as c " + val rs = stmt.executeQuery("SELECT chats.id, chats.name, COUNT(messages.id) as c " +
"FROM chats, messages WHERE messages.source_type IN('group', 'supergroup', 'channel') AND messages.source_id=chats.id " + "FROM chats, messages WHERE messages.source_type IN('group', 'supergroup', 'channel') AND messages.source_id=chats.id " +
"GROUP BY chats.id ORDER BY c DESC") "GROUP BY chats.id ORDER BY c DESC")
while (rs.next()) { while (rs.next()) {
@ -205,18 +176,12 @@ class Database private constructor(var client: TelegramClient) {
} }
rs.close() rs.close()
return list return list
} catch (e: Exception) {
e.printStackTrace()
throw RuntimeException("Exception above!")
}
} }
fun getListOfDialogsForExport(): LinkedList<Dialog> { fun getListOfDialogsForExport(): LinkedList<Dialog> {
val list = LinkedList<Dialog>() val list = LinkedList<Dialog>()
try { val rs = stmt.executeQuery(
val rs = stmt!!.executeQuery(
"SELECT users.id, first_name, last_name, username, COUNT(messages.id) as c " + "SELECT users.id, first_name, last_name, username, COUNT(messages.id) as c " +
"FROM users, messages WHERE messages.source_type='dialog' AND messages.source_id=users.id " + "FROM users, messages WHERE messages.source_type='dialog' AND messages.source_id=users.id " +
"GROUP BY users.id ORDER BY c DESC") "GROUP BY users.id ORDER BY c DESC")
@ -225,21 +190,14 @@ class Database private constructor(var client: TelegramClient) {
} }
rs.close() rs.close()
return list return list
} catch (e: Exception) {
e.printStackTrace()
throw RuntimeException("Exception above!")
} }
}
fun backupDatabase(currentVersion: Int) { fun backupDatabase(currentVersion: Int) {
val filename = String.format(Config.FILE_NAME_DB_BACKUP, currentVersion) val filename = String.format(Config.FILE_NAME_DB_BACKUP, currentVersion)
System.out.println(" Creating a backup of your database as " + filename) System.out.println(" Creating a backup of your database as " + filename)
try { try {
val src = user_manager.fileBase + Config.FILE_NAME_DB val src = file_base + Config.FILE_NAME_DB
val dst = user_manager.fileBase + filename val dst = file_base + filename
logger.debug("Copying {} to {}", src.anonymize(), dst.anonymize()) logger.debug("Copying {} to {}", src.anonymize(), dst.anonymize())
Files.copy( Files.copy(
File(src).toPath(), File(src).toPath(),
@ -256,8 +214,7 @@ class Database private constructor(var client: TelegramClient) {
fun getTopMessageIDForChannel(id: Int): Int = queryInt("SELECT MAX(message_id) FROM messages WHERE source_id=$id AND source_type IN('channel', 'supergroup')") fun getTopMessageIDForChannel(id: Int): Int = queryInt("SELECT MAX(message_id) FROM messages WHERE source_id=$id AND source_type IN('channel', 'supergroup')")
fun logRun(start_id: Int, end_id: Int, count: Int) { fun logRun(start_id: Int, end_id: Int, count: Int) {
try { val ps = conn.prepareStatement("INSERT INTO runs " +
val ps = conn!!.prepareStatement("INSERT INTO runs " +
"(time, start_id, end_id, count_missing) " + "(time, start_id, end_id, count_missing) " +
"VALUES " + "VALUES " +
"(DateTime('now'), ?, ?, ? )") "(DateTime('now'), ?, ?, ? )")
@ -266,27 +223,26 @@ class Database private constructor(var client: TelegramClient) {
ps.setInt(3, count) ps.setInt(3, count)
ps.execute() ps.execute()
ps.close() ps.close()
} catch (e: SQLException) {
}
} }
fun queryInt(query: String): Int { fun queryInt(query: String): Int {
try { val rs = stmt.executeQuery(query)
val rs = stmt!!.executeQuery(query)
rs.next() rs.next()
val result = rs.getInt(1) val result = rs.getInt(1)
rs.close() rs.close()
return result return result
} catch (e: SQLException) {
throw RuntimeException("Could not get count of messages.")
} }
fun queryString(query: String): String {
val rs = stmt.executeQuery(query)
rs.next()
val result = rs.getString(1)
rs.close()
return result
} }
@Synchronized @Synchronized
fun saveMessages(all: TLVector<TLAbsMessage>, api_layer: Int, source_type: MessageSource = MessageSource.NORMAL) { fun saveMessages(all: TLVector<TLAbsMessage>, api_layer: Int, source_type: MessageSource = MessageSource.NORMAL) {
try {
//"(id, dialog_id, from_id, from_type, text, time, has_media, data, sticker, type) " + //"(id, dialog_id, from_id, from_type, text, time, has_media, data, sticker, type) " +
//"VALUES " + //"VALUES " +
//"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); //"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
@ -294,8 +250,8 @@ class Database private constructor(var client: TelegramClient) {
"VALUES " + "VALUES " +
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
//1 2 3 4 5 6 7 8 9 10 11 12 13 14 //1 2 3 4 5 6 7 8 9 10 11 12 13 14
val ps = conn!!.prepareStatement("INSERT OR REPLACE INTO messages " + columns) val ps = conn.prepareStatement("INSERT OR REPLACE INTO messages " + columns)
val ps_insert_or_ignore = conn!!.prepareStatement("INSERT OR IGNORE INTO messages " + columns) val ps_insert_or_ignore = conn.prepareStatement("INSERT OR IGNORE INTO messages " + columns)
for (msg in all) { for (msg in all) {
if (msg is TLMessage) { if (msg is TLMessage) {
@ -307,7 +263,7 @@ class Database private constructor(var client: TelegramClient) {
ps.setInt(4, peer.getChatId()) ps.setInt(4, peer.getChatId())
} else if (peer is TLPeerUser) { } else if (peer is TLPeerUser) {
var id = peer.getUserId() var id = peer.getUserId()
if (id == this.user_manager.user!!.getId()) { if (id == user_manager.id) {
id = msg.getFromId() id = msg.getFromId()
} }
ps.setString(3, "dialog") ps.setString(3, "dialog")
@ -348,7 +304,7 @@ class Database private constructor(var client: TelegramClient) {
} }
ps.setString(7, text) ps.setString(7, text)
ps.setString(8, "" + msg.getDate()) ps.setString(8, "" + msg.getDate())
val f = FileManagerFactory.getFileManager(msg, user_manager, client) val f = FileManagerFactory.getFileManager(msg, user_manager)
if (f == null) { if (f == null) {
ps.setNull(9, Types.BOOLEAN) ps.setNull(9, Types.BOOLEAN)
ps.setNull(10, Types.VARCHAR) ps.setNull(10, Types.VARCHAR)
@ -375,7 +331,7 @@ class Database private constructor(var client: TelegramClient) {
ps.setInt(4, peer.getChatId()) ps.setInt(4, peer.getChatId())
} else if (peer is TLPeerUser) { } else if (peer is TLPeerUser) {
var id = peer.getUserId() var id = peer.getUserId()
if (id == this.user_manager.user!!.getId()) { if (id == user_manager.id) {
id = msg.getFromId() id = msg.getFromId()
} }
ps.setString(3, "dialog") ps.setString(3, "dialog")
@ -423,32 +379,26 @@ class Database private constructor(var client: TelegramClient) {
throw RuntimeException("Unexpected Message type: " + msg.javaClass) throw RuntimeException("Unexpected Message type: " + msg.javaClass)
} }
} }
conn!!.setAutoCommit(false) conn.setAutoCommit(false)
ps.executeBatch() ps.executeBatch()
ps.clearBatch() ps.clearBatch()
ps_insert_or_ignore.executeBatch() ps_insert_or_ignore.executeBatch()
ps_insert_or_ignore.clearBatch() ps_insert_or_ignore.clearBatch()
conn!!.commit() conn.commit()
conn!!.setAutoCommit(true) conn.setAutoCommit(true)
ps.close() ps.close()
ps_insert_or_ignore.close() ps_insert_or_ignore.close()
} catch (e: Exception) {
e.printStackTrace()
throw RuntimeException("Exception shown above happened.")
}
} }
@Synchronized @Synchronized
fun saveChats(all: TLVector<TLAbsChat>) { fun saveChats(all: TLVector<TLAbsChat>) {
try { val ps_insert_or_replace = conn.prepareStatement(
val ps_insert_or_replace = conn!!.prepareStatement(
"INSERT OR REPLACE INTO chats " + "INSERT OR REPLACE INTO chats " +
"(id, name, type) " + "(id, name, type) " +
"VALUES " + "VALUES " +
"(?, ?, ?)") "(?, ?, ?)")
val ps_insert_or_ignore = conn!!.prepareStatement( val ps_insert_or_ignore = conn.prepareStatement(
"INSERT OR IGNORE INTO chats " + "INSERT OR IGNORE INTO chats " +
"(id, name, type) " + "(id, name, type) " +
"VALUES " + "VALUES " +
@ -481,32 +431,26 @@ class Database private constructor(var client: TelegramClient) {
throw RuntimeException("Unexpected " + abs.javaClass) throw RuntimeException("Unexpected " + abs.javaClass)
} }
} }
conn!!.setAutoCommit(false) conn.setAutoCommit(false)
ps_insert_or_ignore.executeBatch() ps_insert_or_ignore.executeBatch()
ps_insert_or_ignore.clearBatch() ps_insert_or_ignore.clearBatch()
ps_insert_or_replace.executeBatch() ps_insert_or_replace.executeBatch()
ps_insert_or_replace.clearBatch() ps_insert_or_replace.clearBatch()
conn!!.commit() conn.commit()
conn!!.setAutoCommit(true) conn.setAutoCommit(true)
ps_insert_or_ignore.close() ps_insert_or_ignore.close()
ps_insert_or_replace.close() ps_insert_or_replace.close()
} catch (e: Exception) {
e.printStackTrace()
throw RuntimeException("Exception shown above happened.")
}
} }
@Synchronized @Synchronized
fun saveUsers(all: TLVector<TLAbsUser>) { fun saveUsers(all: TLVector<TLAbsUser>) {
try { val ps_insert_or_replace = conn.prepareStatement(
val ps_insert_or_replace = conn!!.prepareStatement(
"INSERT OR REPLACE INTO users " + "INSERT OR REPLACE INTO users " +
"(id, first_name, last_name, username, type, phone) " + "(id, first_name, last_name, username, type, phone) " +
"VALUES " + "VALUES " +
"(?, ?, ?, ?, ?, ?)") "(?, ?, ?, ?, ?, ?)")
val ps_insert_or_ignore = conn!!.prepareStatement( val ps_insert_or_ignore = conn.prepareStatement(
"INSERT OR IGNORE INTO users " + "INSERT OR IGNORE INTO users " +
"(id, first_name, last_name, username, type, phone) " + "(id, first_name, last_name, username, type, phone) " +
"VALUES " + "VALUES " +
@ -533,24 +477,20 @@ class Database private constructor(var client: TelegramClient) {
throw RuntimeException("Unexpected " + abs.javaClass) throw RuntimeException("Unexpected " + abs.javaClass)
} }
} }
conn!!.setAutoCommit(false) conn.setAutoCommit(false)
ps_insert_or_ignore.executeBatch() ps_insert_or_ignore.executeBatch()
ps_insert_or_ignore.clearBatch() ps_insert_or_ignore.clearBatch()
ps_insert_or_replace.executeBatch() ps_insert_or_replace.executeBatch()
ps_insert_or_replace.clearBatch() ps_insert_or_replace.clearBatch()
conn!!.commit() conn.commit()
conn!!.setAutoCommit(true) conn.setAutoCommit(true)
ps_insert_or_ignore.close() ps_insert_or_ignore.close()
ps_insert_or_replace.close() ps_insert_or_replace.close()
} catch (e: Exception) {
e.printStackTrace()
throw RuntimeException("Exception shown above happened.")
}
} }
fun fetchSetting(key: String): String? { fun fetchSetting(key: String): String? {
val rs = stmt!!.executeQuery("SELECT value FROM settings WHERE key='${key}'") val rs = stmt.executeQuery("SELECT value FROM settings WHERE key='${key}'")
rs.next() rs.next()
val result = rs.getString(1) val result = rs.getString(1)
rs.close() rs.close()
@ -558,7 +498,7 @@ class Database private constructor(var client: TelegramClient) {
} }
fun saveSetting(key: String, value: String?) { fun saveSetting(key: String, value: String?) {
val ps = conn!!.prepareStatement("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)") val ps = conn.prepareStatement("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)")
ps.setString(1, key) ps.setString(1, key)
if (value==null) { if (value==null) {
ps.setNull(2, Types.VARCHAR) ps.setNull(2, Types.VARCHAR)
@ -570,56 +510,37 @@ class Database private constructor(var client: TelegramClient) {
} }
fun getIdsFromQuery(query: String): LinkedList<Int> { fun getIdsFromQuery(query: String): LinkedList<Int> {
try {
val list = LinkedList<Int>() val list = LinkedList<Int>()
val rs = stmt!!.executeQuery(query) val rs = stmt.executeQuery(query)
while (rs.next()) { while (rs.next()) {
list.add(rs.getInt(1)) list.add(rs.getInt(1))
} }
rs.close() rs.close()
return list return list
} catch (e: SQLException) {
throw RuntimeException(e)
}
} }
fun getMessageTypesWithCount(c: AbstractChat): HashMap<String, Int> { fun getMessageTypesWithCount(c: AbstractChat): HashMap<String, Int> {
val map = HashMap<String, Int>() val map = HashMap<String, Int>()
try { val rs = stmt.executeQuery("SELECT message_type, COUNT(message_id) FROM messages WHERE " + c.query + " GROUP BY message_type")
val rs = stmt!!.executeQuery("SELECT message_type, COUNT(message_id) FROM messages WHERE " + c.query + " GROUP BY message_type")
while (rs.next()) { while (rs.next()) {
map.put("count.messages.type." + rs.getString(1), rs.getInt(2)) map.put("count.messages.type." + rs.getString(1), rs.getInt(2))
} }
rs.close() rs.close()
return map return map
} catch (e: Exception) {
throw RuntimeException(e)
}
} }
fun getMessageMediaTypesWithCount(c: AbstractChat): HashMap<String, Int> { fun getMessageMediaTypesWithCount(c: AbstractChat): HashMap<String, Int> {
val map = HashMap<String, Int>() val map = HashMap<String, Int>()
try {
var count = 0 var count = 0
val rs = stmt!!.executeQuery("SELECT media_type, COUNT(message_id) FROM messages WHERE " + c.query + " GROUP BY media_type") val rs = stmt.executeQuery("SELECT media_type, COUNT(message_id) FROM messages WHERE " + c.query + " GROUP BY media_type")
while (rs.next()) { while (rs.next()) {
var s = rs.getString(1) var type = rs.getString(1) ?: "null"
if (s == null) { if (type != "null") count += rs.getInt(2)
s = "null" map.put("count.messages.media_type.${type}", rs.getInt(2))
} else {
count += rs.getInt(2)
}
map.put("count.messages.media_type.$s", rs.getInt(2))
} }
map.put("count.messages.media_type.any", count) map.put("count.messages.media_type.any", count)
rs.close() rs.close()
return map return map
} catch (e: Exception) {
throw RuntimeException(e)
}
} }
fun getMessageAuthorsWithCount(c: AbstractChat): HashMap<String, Any> { fun getMessageAuthorsWithCount(c: AbstractChat): HashMap<String, Any> {
@ -629,8 +550,7 @@ class Database private constructor(var client: TelegramClient) {
// Set a default value for 'me' to fix the charts for channels - cause I // Set a default value for 'me' to fix the charts for channels - cause I
// possibly didn't send any messages there. // possibly didn't send any messages there.
map.put("authors.count.me", 0) map.put("authors.count.me", 0)
try { val rs = stmt.executeQuery("SELECT users.id, users.first_name, users.last_name, users.username, COUNT(messages.id) " +
val rs = stmt!!.executeQuery("SELECT users.id, users.first_name, users.last_name, users.username, COUNT(messages.id) " +
"FROM messages " + "FROM messages " +
"LEFT JOIN users ON users.id=messages.sender_id " + "LEFT JOIN users ON users.id=messages.sender_id " +
"WHERE " + c.query + " GROUP BY sender_id") "WHERE " + c.query + " GROUP BY sender_id")
@ -656,23 +576,13 @@ class Database private constructor(var client: TelegramClient) {
map.put("authors.all", all_data) map.put("authors.all", all_data)
rs.close() rs.close()
return map return map
} catch (e: Exception) {
throw RuntimeException(e)
}
} }
fun getMessageCountForExport(c: AbstractChat): Int { fun getMessageCountForExport(c: AbstractChat): Int = queryInt("SELECT COUNT(*) FROM messages WHERE " + c.query)
val rs = stmt!!.executeQuery("SELECT COUNT(*) FROM messages WHERE " + c.query);
rs.next()
val result = rs.getInt(1)
rs.close()
return result
}
fun getMessageTimesMatrix(c: AbstractChat): Array<IntArray> { fun getMessageTimesMatrix(c: AbstractChat): Array<IntArray> {
val result = Array(7) { IntArray(24) } val result = Array(7) { IntArray(24) }
try { val rs = stmt.executeQuery("SELECT STRFTIME('%w', time, 'unixepoch') as DAY, " +
val rs = stmt!!.executeQuery("SELECT STRFTIME('%w', time, 'unixepoch') as DAY, " +
"STRFTIME('%H', time, 'unixepoch') AS hour, " + "STRFTIME('%H', time, 'unixepoch') AS hour, " +
"COUNT(id) FROM messages WHERE " + c.query + " GROUP BY hour, day " + "COUNT(id) FROM messages WHERE " + c.query + " GROUP BY hour, day " +
"ORDER BY hour, day") "ORDER BY hour, day")
@ -681,14 +591,9 @@ class Database private constructor(var client: TelegramClient) {
} }
rs.close() rs.close()
return result return result
} catch (e: Exception) {
throw RuntimeException(e)
}
} }
fun getMessagesForExport(c: AbstractChat, limit: Int=-1, offset: Int=0): LinkedList<HashMap<String, Any>> { fun getMessagesForExport(c: AbstractChat, limit: Int=-1, offset: Int=0): LinkedList<HashMap<String, Any>> {
try {
var query = "SELECT messages.message_id as message_id, text, time*1000 as time, has_media, " + var query = "SELECT messages.message_id as message_id, text, time*1000 as time, has_media, " +
"media_type, media_file, media_size, users.first_name as user_first_name, users.last_name as user_last_name, " + "media_type, media_file, media_size, users.first_name as user_first_name, users.last_name as user_last_name, " +
"users.username as user_username, users.id as user_id, " + "users.username as user_username, users.id as user_id, " +
@ -703,7 +608,7 @@ class Database private constructor(var client: TelegramClient) {
query = query + " LIMIT ${limit} OFFSET ${offset}" query = query + " LIMIT ${limit} OFFSET ${offset}"
} }
val rs = stmt!!.executeQuery(query) val rs = stmt.executeQuery(query)
val format_time = SimpleDateFormat("HH:mm:ss") val format_time = SimpleDateFormat("HH:mm:ss")
val format_date = SimpleDateFormat("d MMM yy") val format_date = SimpleDateFormat("d MMM yy")
@ -727,7 +632,7 @@ class Database private constructor(var client: TelegramClient) {
if (rs.getString("media_type") != null) { if (rs.getString("media_type") != null) {
h.put("media_" + rs.getString("media_type"), true) h.put("media_" + rs.getString("media_type"), true)
} }
h.put("from_me", rs.getInt("user_id") == user_manager.user!!.getId()) h.put("from_me", rs.getInt("user_id") == user_manager.id)
h.put("is_new_date", !date.equals(old_date)) h.put("is_new_date", !date.equals(old_date))
h.put("odd_even", if (count % 2 == 0) "even" else "odd") h.put("odd_even", if (count % 2 == 0) "even" else "odd")
h.put("same_user", old_user != 0 && rs.getInt("user_id") == old_user) h.put("same_user", old_user != 0 && rs.getInt("user_id") == old_user)
@ -739,11 +644,6 @@ class Database private constructor(var client: TelegramClient) {
} }
rs.close() rs.close()
return list return list
} catch (e: Exception) {
e.printStackTrace()
throw RuntimeException("Exception above!")
}
} }
@ -753,21 +653,13 @@ class Database private constructor(var client: TelegramClient) {
} }
inner class Dialog(var id: Int, var first_name: String?, var last_name: String?, var username: String?, var count: Int?) : AbstractChat() { inner class Dialog(var id: Int, var first_name: String?, var last_name: String?, var username: String?, var count: Int?) : AbstractChat() {
override val query = "source_type='dialog' AND source_id=" + id
override val query: String override val type = "dialog"
get() = "source_type='dialog' AND source_id=" + id
override val type: String
get() = "dialog"
} }
inner class Chat(var id: Int, var name: String?, var count: Int?) : AbstractChat() { inner class Chat(var id: Int, var name: String?, var count: Int?) : AbstractChat() {
override val query = "source_type IN('group', 'supergroup', 'channel') AND source_id=" + id
override val query: String override val type = "chat"
get() = "source_type IN('group', 'supergroup', 'channel') AND source_id=" + id
override val type: String
get() = "chat"
} }
inner class User(id: Int, first_name: String?, last_name: String?) { inner class User(id: Int, first_name: String?, last_name: String?) {
@ -775,7 +667,7 @@ class Database private constructor(var client: TelegramClient) {
var isMe: Boolean = false var isMe: Boolean = false
init { init {
isMe = id == user_manager.user!!.getId() isMe = id == user_manager.id
val s = StringBuilder() val s = StringBuilder()
if (first_name != null) s.append(first_name + " ") if (first_name != null) s.append(first_name + " ")
if (last_name != null) s.append(last_name) if (last_name != null) s.append(last_name)
@ -784,11 +676,8 @@ class Database private constructor(var client: TelegramClient) {
} }
inner class GlobalChat : AbstractChat() { inner class GlobalChat : AbstractChat() {
override val query: String override val query = "1=1"
get() = "1=1" override val type = "GlobalChat"
override val type: String
get() = "GlobalChat"
} }
companion object { companion object {

View File

@ -313,7 +313,7 @@ internal class DB_Update_6(conn: Connection, db: Database) : DatabaseUpdate(conn
} else { } else {
ps.setInt(1, msg.getFwdFrom().getFromId()) ps.setInt(1, msg.getFwdFrom().getFromId())
} }
val f = FileManagerFactory.getFileManager(msg, db.user_manager, db.client) val f = FileManagerFactory.getFileManager(msg, db.user_manager)
if (f == null) { if (f == null) {
ps.setNull(2, Types.VARCHAR) ps.setNull(2, Types.VARCHAR)
ps.setNull(3, Types.VARCHAR) ps.setNull(3, Types.VARCHAR)

View File

@ -1,8 +1,8 @@
package de.fabianonline.telegram_backup package de.fabianonline.telegram_backup
class DbSettings() { class DbSettings(val database: Database) {
private fun fetchValue(name: String): String? = Database.getInstance().fetchSetting(name) private fun fetchValue(name: String): String? = database.fetchSetting(name)
private fun saveValue(name: String, value: String?) = Database.getInstance().saveSetting(name, value) private fun saveValue(name: String, value: String?) = database.saveSetting(name, value)
var pts: String? var pts: String?
get() = fetchValue("pts") get() = fetchValue("pts")

View File

@ -61,18 +61,9 @@ enum class MessageSource(val descr: String) {
SUPERGROUP("supergroup") SUPERGROUP("supergroup")
} }
class DownloadManager(internal var client: TelegramClient?, p: DownloadProgressInterface) { class DownloadManager(val client: TelegramClient, val prog: DownloadProgressInterface, val db: Database, val user_manager: UserManager, val inisettings: IniSettings) {
internal var user: UserManager? = null
internal var db: Database? = null
internal var prog: DownloadProgressInterface? = null
internal var has_seen_flood_wait_message = false internal var has_seen_flood_wait_message = false
init {
this.user = UserManager.getInstance()
this.prog = p
this.db = Database.getInstance()
}
@Throws(RpcErrorException::class, IOException::class) @Throws(RpcErrorException::class, IOException::class)
fun downloadMessages(limit: Int?) { fun downloadMessages(limit: Int?) {
var completed: Boolean var completed: Boolean
@ -173,20 +164,16 @@ class DownloadManager(internal var client: TelegramClient?, p: DownloadProgressI
} }
*/ */
if (IniSettings.download_channels || IniSettings.download_supergroups) { if (inisettings.download_channels) {
// TODO Add chat title (and other stuff?) to the database
if (IniSettings.download_channels) {
println("Checking channels...") println("Checking channels...")
for (channel in chats.channels) { if (channel.download) downloadMessagesFromChannel(channel) } for (channel in chats.channels) { if (channel.download) downloadMessagesFromChannel(channel) }
} }
if (IniSettings.download_supergroups) { if (inisettings.download_supergroups) {
println("Checking supergroups...") println("Checking supergroups...")
for (supergroup in chats.supergroups) { if (supergroup.download) downloadMessagesFromChannel(supergroup) } for (supergroup in chats.supergroups) { if (supergroup.download) downloadMessagesFromChannel(supergroup) }
} }
} }
}
private fun downloadMessagesFromChannel(channel: Channel) { private fun downloadMessagesFromChannel(channel: Channel) {
val obj = channel.obj val obj = channel.obj
@ -315,7 +302,7 @@ class DownloadManager(internal var client: TelegramClient?, p: DownloadProgressI
prog!!.onMediaDownloadStart(messages.size) prog!!.onMediaDownloadStart(messages.size)
for (msg in messages) { for (msg in messages) {
if (msg == null) continue if (msg == null) continue
val m = FileManagerFactory.getFileManager(msg, user!!, client!!) val m = FileManagerFactory.getFileManager(msg, user_manager)
logger.trace("message {}, {}, {}, {}, {}", logger.trace("message {}, {}, {}, {}, {}",
msg.getId(), msg.getId(),
msg.getMedia().javaClass.getSimpleName().replace("TLMessageMedia", ""), msg.getMedia().javaClass.getSimpleName().replace("TLMessageMedia", ""),
@ -366,10 +353,10 @@ class DownloadManager(internal var client: TelegramClient?, p: DownloadProgressI
if (tl_peer_channel == null) continue if (tl_peer_channel == null) continue
var download = true var download = true
if (IniSettings.whitelist_channels != null) { if (inisettings.whitelist_channels != null) {
download = IniSettings.whitelist_channels!!.contains(tl_channel.getId().toString()) download = inisettings.whitelist_channels.contains(tl_channel.getId().toString())
} else if (IniSettings.blacklist_channels != null) { } else if (inisettings.blacklist_channels != null) {
download = !IniSettings.blacklist_channels!!.contains(tl_channel.getId().toString()) download = !inisettings.blacklist_channels.contains(tl_channel.getId().toString())
} }
val channel = Channel(id=tl_channel.getId(), access_hash=tl_channel.getAccessHash(), title=tl_channel.getTitle(), obj=tl_peer_channel, download=download) val channel = Channel(id=tl_channel.getId(), access_hash=tl_channel.getAccessHash(), title=tl_channel.getTitle(), obj=tl_peer_channel, download=download)
if (tl_channel.getMegagroup()) { if (tl_channel.getMegagroup()) {

View File

@ -1,85 +0,0 @@
/* Telegram_Backup
* Copyright (C) 2016 Fabian Schlenz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
package de.fabianonline.telegram_backup
import javax.swing.*
import javax.swing.event.ListSelectionEvent
import javax.swing.event.ListSelectionListener
import java.awt.*
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.util.Vector
class GUIController() {
init {
showAccountChooserDialog()
}
private fun showAccountChooserDialog() {
val accountChooser = JDialog()
accountChooser.setTitle("Choose account")
accountChooser.setSize(400, 200)
val vert = JPanel()
vert.setLayout(BorderLayout())
vert.add(JLabel("Please select the account to use or create a new one."), BorderLayout.NORTH)
val accounts = Utils.getAccounts()
val list = JList<String>(accounts)
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
vert.add(list, BorderLayout.CENTER)
val bottom = JPanel(GridLayout(1, 2))
val btnAddAccount = JButton("Add account")
bottom.add(btnAddAccount)
val btnLogin = JButton("Login")
btnLogin.setEnabled(false)
bottom.add(btnLogin)
vert.add(bottom, BorderLayout.SOUTH)
accountChooser.add(vert)
accountChooser.setVisible(true)
accountChooser.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE)
}
private fun addAccountDialog() {
val loginDialog = JDialog()
loginDialog.setTitle("Add an account")
loginDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE)
val sections = JPanel()
sections.setLayout(BoxLayout(sections, BoxLayout.Y_AXIS))
val top = JPanel()
top.setLayout(BoxLayout(top, BoxLayout.Y_AXIS))
top.add(JLabel("Please enter your phone number in international format:"))
top.add(JTextField("+49123773212"))
sections.add(top)
sections.add(Box.createVerticalStrut(5))
sections.add(JSeparator(SwingConstants.HORIZONTAL))
val middle = JPanel()
middle.setLayout(BoxLayout(middle, BoxLayout.Y_AXIS))
middle.add(JLabel("Telegram sent you a code. Enter it here:"))
middle.add(JTextField())
middle.setEnabled(false)
sections.add(middle)
sections.add(Box.createVerticalStrut(5))
sections.add(JSeparator(SwingConstants.HORIZONTAL))
loginDialog.add(sections)
loginDialog.setVisible(true)
}
}

View File

@ -4,19 +4,14 @@ import java.io.File
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.slf4j.Logger import org.slf4j.Logger
object IniSettings { class IniSettings(val file_base: String) {
val logger = LoggerFactory.getLogger(IniSettings::class.java) val logger = LoggerFactory.getLogger(IniSettings::class.java)
var settings = mutableMapOf<String, MutableList<String>>() var settings = mutableMapOf<String, MutableList<String>>()
init { init {
if (UserManager.getInstance().user != null) { loadIni(file_base + "config.ini")
loadIni(UserManager.getInstance().fileBase + "config.ini") copySampleIni(file_base + "config.sample.ini")
copySampleIni(UserManager.getInstance().fileBase + "config.sample.ini")
} }
}
// Dummy function that can be called to force this object to run its init-code.
fun load() { }
private fun loadIni(filename: String) { private fun loadIni(filename: String) {
val file = File(filename) val file = File(filename)
@ -66,20 +61,12 @@ object IniSettings {
} }
fun getArray(key: String): List<String> = settings.get(key) ?: listOf<String>() fun getArray(key: String): List<String> = settings.get(key) ?: listOf<String>()
val gmaps_key: String val gmaps_key = getString("gmaps_key", default=Config.SECRET_GMAPS)!!
get() = getString("gmaps_key", default=Config.SECRET_GMAPS)!! val pagination = getBoolean("pagination", default=true)
val pagination: Boolean val pagination_size = getInt("pagination_size", default=Config.DEFAULT_PAGINATION)!!
get() = getBoolean("pagination", default=true) val download_media = getBoolean("download_media", default=true)
val pagination_size: Int val download_channels = getBoolean("download_channels", default=false)
get() = getInt("pagination_size", default=Config.DEFAULT_PAGINATION)!! val download_supergroups = getBoolean("download_supergroups", default=false)
val download_media: Boolean val whitelist_channels = getStringList("whitelist_channels")
get() = getBoolean("download_media", default=true) val blacklist_channels = getStringList("blacklist_channels")
val download_channels: Boolean
get() = getBoolean("download_channels", default=false)
val download_supergroups: Boolean
get() = getBoolean("download_supergroups", default=false)
val whitelist_channels: List<String>?
get() = getStringList("whitelist_channels")
val blacklist_channels: List<String>?
get() = getStringList("blacklist_channels")
} }

View File

@ -0,0 +1,87 @@
package de.fabianonline.telegram_backup
import com.github.badoualy.telegram.tl.api.auth.TLSentCode
class LoginManager(val app: TelegramApp, val target_dir: String, val phoneToUse: String?) {
fun run() {
var phone: String
if (phoneToUse == null) {
println("Please enter your phone number in international format.")
println("Example: +4917077651234")
phone = getLine()
} else {
phone = phoneToUse
}
val file_base = CommandLineController.build_file_base(target_dir, phone)
// We now have an account, so we can create an ApiStorage and TelegramClient.
val storage = ApiStorage(file_base)
val client = Kotlogram.getDefaultClient(app, storage, Kotlogram.PROD_DC4, null)
val sent_code = send_code_to_phone_number(client, phone)
println("Telegram sent you a code. Please enter it here.")
val code = getLine()
try {
verify_code(client, phone, sent_code, code)
} catch(e: PasswordNeededException) {
println("We also need your account password. Please enter it now. It should not be printed, so it's okay if you see nothing while typing it.")
val pw = getPassword()
verify_password(client, pw)
}
System.out.println("Everything seems fine. Please run this tool again with '--account +" + user.user!!.getPhone().anonymize() + " to use this account.")
}
private fun send_code_to_phone_number(client: TelegramClient, phone: String): TLSentCode {
return client.authSendCode(false, phone, true)
}
private fun verify_code(client: TelegramClient, phone: String, sent_code: TLSentCode, code: String): TLUser {
try {
val auth = client.authSignIn(phone, sent_code.getPhoneCodeHash(), code)
return auth.getUser().getAsUser()
} catch (e: RpcErrorException) {
if (e.getCode() == 401 && e.getTag()=="SESSION_PASSWORD_NEEDED") {
throw PasswordNeededException()
} else {
throw e
}
}
}
private fun verify_password(client: TelegramClient, password: String): TLUser {
val pw = password.toByteArray(charset = Charsets.UTF_8)
val salt = (client.accountGetPassword() as TLPassword).getCurrentSalt().getData()
val md = MessageDigest.getInstance("SHA-256")
val salted = ByteArray(2 * salt.size + pw.size)
System.arraycopy(salt, 0, salted, 0, salt.size)
System.arraycopy(pw, 0, salted, salt.size, pw.size)
System.arraycopy(salt, 0, salted, salt.size + pw.size, salt.size)
val hash = md.digest(salted)
val auth = client.authCheckPassword(TLBytes(hash))
return auth.getUser().getAsUser()
}
private fun getLine(): String {
if (System.console() != null) {
return System.console().readLine("> ")
} else {
print("> ")
return Scanner(System.`in`).nextLine()
}
}
private fun getPassword(): String {
if (System.console() != null) {
return String(System.console().readPassword("> "))
} else {
return getLine()
}
}
}
class PasswordNeededException: Exception("A password is needed to be able to login to this account.") {}

View File

@ -34,107 +34,34 @@ import java.io.File
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.slf4j.Logger import org.slf4j.Logger
class UserManager @Throws(IOException::class) class UserManager(val client: TelegramClient) {
private constructor(c: TelegramClient) { val tl_user: TLUser
var user: TLUser? = null val logger = LoggerFactory.getLogger(UserManager::class.java)
var phone: String? = null val phone: String
private var code: String? = null get() = "+" + tl_user.getPhone()
private val client: TelegramClient val id: Int
private var sent_code: TLSentCode? = null get() = tl_user.getId()
private var auth: TLAuthorization? = null
var isPasswordNeeded = false
private set
val loggedIn: Boolean init {
get() = user != null logger.debug("Calling getFullUser")
val full_user = client.usersGetFullUser(TLInputUserSelf())
tl_user = full_user.getUser().getAsUser()
}
val userString: String fun toString(): String {
get() {
if (this.user == null) return "Not logged in"
val sb = StringBuilder() val sb = StringBuilder()
if (this.user!!.getFirstName() != null) { sb.append(tl_user.getFirstName() ?: "")
sb.append(this.user!!.getFirstName()) if (tl_user.getLastName() != null) {
}
if (this.user!!.getLastName() != null) {
sb.append(" ") sb.append(" ")
sb.append(this.user!!.getLastName()) sb.append(tl_user.getLastName())
} }
if (this.user!!.getUsername() != null) { if (tl_user.getUsername() != null) {
sb.append(" (@") sb.append(" (@")
sb.append(this.user!!.getUsername()) sb.append(tl_user.getUsername())
sb.append(")") sb.append(")")
} }
return sb.toString() return sb.toString()
} }
val fileBase: String
get() = Config.FILE_BASE + File.separatorChar + "+" + this.user!!.getPhone() + File.separatorChar
init {
this.client = c
logger.debug("Calling getFullUser")
try {
val full_user = this.client.usersGetFullUser(TLInputUserSelf())
this.user = full_user.getUser().getAsUser()
} catch (e: RpcErrorException) {
// This may happen. Ignoring it.
logger.debug("Ignoring exception:", e)
}
}
@Throws(RpcErrorException::class, IOException::class)
fun sendCodeToPhoneNumber(number: String) {
this.phone = number
this.sent_code = this.client.authSendCode(false, number, true)
}
@Throws(RpcErrorException::class, IOException::class)
fun verifyCode(code: String) {
this.code = code
try {
this.auth = client.authSignIn(phone, this.sent_code!!.getPhoneCodeHash(), this.code)
this.user = auth!!.getUser().getAsUser()
} catch (e: RpcErrorException) {
if (e.getCode() != 401 || !e.getTag().equals("SESSION_PASSWORD_NEEDED")) throw e
this.isPasswordNeeded = true
}
}
@Throws(RpcErrorException::class, IOException::class)
fun verifyPassword(pw: String) {
val password = pw.toByteArray(charset = Charsets.UTF_8)
val salt = (client.accountGetPassword() as TLPassword).getCurrentSalt().getData()
var md: MessageDigest
try {
md = MessageDigest.getInstance("SHA-256")
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
return
}
val salted = ByteArray(2 * salt.size + password.size)
System.arraycopy(salt, 0, salted, 0, salt.size)
System.arraycopy(password, 0, salted, salt.size, password.size)
System.arraycopy(salt, 0, salted, salt.size + password.size, salt.size)
val hash = md.digest(salted)
auth = client.authCheckPassword(TLBytes(hash))
this.user = auth!!.getUser().getAsUser()
}
companion object {
private val logger = LoggerFactory.getLogger(UserManager::class.java)
internal var instance: UserManager? = null
@Throws(IOException::class)
fun init(c: TelegramClient) {
instance = UserManager(c)
}
fun getInstance(): UserManager {
if (instance == null) throw RuntimeException("UserManager is not yet initialized.")
return instance!!
}
}
} }

View File

@ -43,7 +43,7 @@ import java.util.concurrent.TimeoutException
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
abstract class AbstractMediaFileManager(protected var message: TLMessage, protected var user: UserManager, protected var client: TelegramClient) { abstract class AbstractMediaFileManager(protected var message: TLMessage, protected var user: UserManager) {
open var isEmpty = false open var isEmpty = false
abstract val size: Int abstract val size: Int
abstract val extension: String abstract val extension: String

View File

@ -42,7 +42,7 @@ import java.util.concurrent.TimeoutException
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
open class DocumentFileManager(msg: TLMessage, user: UserManager, client: TelegramClient) : AbstractMediaFileManager(msg, user, client) { open class DocumentFileManager(msg: TLMessage, user: UserManager) : AbstractMediaFileManager(msg, user) {
protected var doc: TLDocument? = null protected var doc: TLDocument? = null
override lateinit var extension: String override lateinit var extension: String

View File

@ -42,29 +42,29 @@ import java.util.concurrent.TimeoutException
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
object FileManagerFactory { object FileManagerFactory {
fun getFileManager(m: TLMessage?, u: UserManager, c: TelegramClient): AbstractMediaFileManager? { fun getFileManager(m: TLMessage?, u: UserManager): AbstractMediaFileManager? {
if (m == null) return null if (m == null) return null
val media = m.getMedia() ?: return null val media = m.getMedia() ?: return null
if (media is TLMessageMediaPhoto) { if (media is TLMessageMediaPhoto) {
return PhotoFileManager(m, u, c) return PhotoFileManager(m, u)
} else if (media is TLMessageMediaDocument) { } else if (media is TLMessageMediaDocument) {
val d = DocumentFileManager(m, u, c) val d = DocumentFileManager(m, u)
return if (d.isSticker) { return if (d.isSticker) {
StickerFileManager(m, u, c) StickerFileManager(m, u)
} else d } else d
} else if (media is TLMessageMediaGeo) { } else if (media is TLMessageMediaGeo) {
return GeoFileManager(m, u, c) return GeoFileManager(m, u)
} else if (media is TLMessageMediaEmpty) { } else if (media is TLMessageMediaEmpty) {
return UnsupportedFileManager(m, u, c, "empty") return UnsupportedFileManager(m, u, "empty")
} else if (media is TLMessageMediaUnsupported) { } else if (media is TLMessageMediaUnsupported) {
return UnsupportedFileManager(m, u, c, "unsupported") return UnsupportedFileManager(m, u, "unsupported")
} else if (media is TLMessageMediaWebPage) { } else if (media is TLMessageMediaWebPage) {
return UnsupportedFileManager(m, u, c, "webpage") return UnsupportedFileManager(m, u, "webpage")
} else if (media is TLMessageMediaContact) { } else if (media is TLMessageMediaContact) {
return UnsupportedFileManager(m, u, c, "contact") return UnsupportedFileManager(m, u, "contact")
} else if (media is TLMessageMediaVenue) { } else if (media is TLMessageMediaVenue) {
return UnsupportedFileManager(m, u, c, "venue") return UnsupportedFileManager(m, u, "venue")
} else { } else {
AbstractMediaFileManager.throwUnexpectedObjectError(media) AbstractMediaFileManager.throwUnexpectedObjectError(media)
} }

View File

@ -43,7 +43,7 @@ import java.util.concurrent.TimeoutException
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
class GeoFileManager(msg: TLMessage, user: UserManager, client: TelegramClient) : AbstractMediaFileManager(msg, user, client) { class GeoFileManager(msg: TLMessage, user: UserManager) : AbstractMediaFileManager(msg, user) {
protected lateinit var geo: TLGeoPoint protected lateinit var geo: TLGeoPoint
// We don't know the size, so we just guess. // We don't know the size, so we just guess.

View File

@ -42,7 +42,7 @@ import java.util.concurrent.TimeoutException
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
class PhotoFileManager(msg: TLMessage, user: UserManager, client: TelegramClient) : AbstractMediaFileManager(msg, user, client) { class PhotoFileManager(msg: TLMessage, user: UserManager) : AbstractMediaFileManager(msg, user) {
private lateinit var photo: TLPhoto private lateinit var photo: TLPhoto
override var size = 0 override var size = 0
private lateinit var photo_size: TLPhotoSize private lateinit var photo_size: TLPhotoSize

View File

@ -50,7 +50,7 @@ import java.util.concurrent.TimeoutException
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
class StickerFileManager(msg: TLMessage, user: UserManager, client: TelegramClient) : DocumentFileManager(msg, user, client) { class StickerFileManager(msg: TLMessage, user: UserManager) : DocumentFileManager(msg, user) {
override val isSticker = true override val isSticker = true

View File

@ -43,7 +43,7 @@ import java.util.concurrent.TimeoutException
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
class UnsupportedFileManager(msg: TLMessage, user: UserManager, client: TelegramClient, type: String) : AbstractMediaFileManager(msg, user, client) { class UnsupportedFileManager(msg: TLMessage, user: UserManager, type: String) : AbstractMediaFileManager(msg, user) {
override var name = type override var name = type
override val targetFilename = "" override val targetFilename = ""
override val targetPath = "" override val targetPath = ""