#!/usr/bin/env node var data = {} // Hold all global data var os = require('os') var fs = require('fs') var moment = require('moment') var blessed = require('blessed') var path = require('path') data.cfgDir = path.join(process.env.XDG_CONFIG_HOME || (path.join(process.env.HOME || process.env.USERPROFILE, '/.config/')), 'telecommander/') process.env.LOGGER_FILE = process.env.LOGGER_FILE || "/tmp/telecommander" data.keyFile = path.join(data.cfgDir,'key') data.userFile = path.join(data.cfgDir,'user_data.json') data.telegramLink = require('telegram.link')() // Load modules require('./lib/cli.js')(data) // Parse command line args require('./lib/util.js')(data) // Load utils require('./lib/ui.js')(data) // Load ui /* IF YOU FORK THE APP PLEASE CHANGE THE ID * AND HASH IN THE APP OBJECT! THEY IDENTIFY * THE APPLICATION CREATOR AND YOU CAN * OBTAIN YOURS FROM http://my.telegram.org */ data.app = { id: '42419', hash: '90a3c2cdbf9b391d9ed72c0639dc0786', version: require('./package.json').version, lang: 'en', deviceModel: os.type(), systemVersion: os.platform()+'/'+os.release() } // Logger var getLogger = require('get-log') getLogger.PROJECT_NAME = 'telecommander' data.logger = getLogger('main') data.authKey // our authorization key to access telegram data.connected = false // keep track of wether we are good to go and logged in // Write something in the Status box data.log = function(){ args = Array.prototype.slice.call(arguments) var msg = args.join(' ') data.getMsgBox(data.statusWindow).add(msg) data.logger.info(msg) } data.command = function(cmd){ cmdl = cmd.split(' ') cmdname = cmdl[0] if(cmdname === 'phone'){ // So the user can provide his phone numbah if(data.connected){ return log("Silly user, you're already connected! We don't need that phone number") } data.user.phone = cmd.split(' ')[1] var mindate = moment() data.log('Checking your phone number with Telegram...') data.client.auth.sendCode(data.user.phone,5,'en',function(result){ if(result.err_code){ return data.log('Errors:',result.error_code,result.error_message) } //data.log('Res:',JSON.stringify(result)) data.user.registered = result.phone_registered data.user.phoneCodeHash = result.phone_code_hash function gmd(){ var m = moment() m = m.subtract(m.diff(mindate)) return 'Please use a telegram code not older than '+m.fromNow(true) } if(!data.user.registered){ data.log("Your number is not registered. Telecommander will register your account with the Telegram service") data.log(gmd()) data.log('Ready for phone code, use command: "code " to register') data.log("If you don't want to sign up, just don't enter the code and press ESC to exit. No data was saved to the file system") } else { data.log("Your number is already assigned to a Telegram account. Telecommander will log you in.") data.log(gmd()) data.log("If you don't want to sign in, just don't enter the code and press ESC to exit. No data was saved to the file system") } }) } else if(cmdname === 'code'){ // So the user can provide his phone code if(data.connected){ return data.log("Silly user, you're already connected! We don't need that phone code") } code = cmdl[1] name = cmdl[2] lastname = cmdl[3] if(((!name || !lastname) && !data.user.registered) || !code) return log('insufficient arguments:',cmd) var cb = function(result){ data.user.id = ''+result.user.id data.user.phone = result.user.phone data.user.phoneCodeHash = result.phone_code_hash data.user.username = result.user.username data.user.first_name = result.user.first_name data.user.last_name = result.user.last_name // Done, write user data and key to disk try { fs.mkdirSync(data.cfgDir,'0770') } catch (e) { if(e.code != 'EEXIST'){ console.error("FATAL: couldn't create configuration directory",data.cfgDir,e) process.exit(-1) } } data.log('Writing Log In token and user data to',data.cfgDir) fs.writeFile(data.cfgDir+'key',data.app.authKey,function(err){ if(err) data.log('FATAL: Could not write key to disk:',err) }) fs.writeFile(data.cfgDir+'user_data.json',JSON.stringify(data.user),function(err){ if(err) data.log("FATAL: couldn't write user_data.json:",err) }) data.whenReady() } // Log in finally if(data.user.registered) data.client.auth.signIn(data.user.phone,data.user.phoneCodeHash,code,cb) else data.client.auth.signUp(data.user.phone,data.user.phoneCodeHash,code,name,lastname,cb) } else { data.log('Command not found.') } } // Send a message data.sendMsg = function(name,str){ if(!data.connected){ return log('Error: not ready to send messages') } var obj = data.nameToObj(name) var peer = data.idToPeer(obj.id,obj.title?'group':'user') var randid = parseInt(Math.random() * 1000000000) //log('Sending Message to:',peer.toPrintable()) data.client.messages.sendMessage(peer,str,randid,function(sent){ //log('Sent message:','"'+str+'"','to:',selectedWindow+':',sent.toPrintable()) }) } // Connects to telegram data.connect = function(){ data.client = data.telegramLink.createClient(data.app, data.dataCenter, function(){ if(!data.app.authKey){ data.log('Downloading Authorization Key...') data.client.createAuthKey(function(auth){ data.app.authKey = auth.key.encrypt('password') // Will add security later, I promise // Writes the new encrypted key to disk data.log('Ready for phone number, use command: phone ') }) } else { data.whenReady() } }) data.client.once('dataCenter',function(dcs){ data.log('Datacenters:',dcs.toPrintable()) }) } // Executed when connected and logged in data.whenReady = function(){ data.log('Connected') data.connected = true data.downloadData() data.chats.focus() } // Downloads stuff data.downloadData = function(){ data.log('Downloading data...') data.client.contacts.getContacts('',function(cont){ //data.chats.clearItems() //data.chats.add(data.statusWindow) cont.users.list.forEach(data.addUser) }) data.client.messages.getDialogs(0,0,10,function(dialogs){ if(dialogs && dialogs.chats && dialogs.chats.list) dialogs.chats.list.forEach(data.addGroup) }) data.client.updates.getState(function(astate){ data.updateState(astate) data.log(data.state.unreadCount,'unread messages') //data.log('Started receiving updates') // Can't use registerOnUpdates because it's apparently broken //client.registerOnUpdates(onUpdate) setTimeout(data.downloadUpdates,1000) }) } data.downloadUpdates = function(){ data.client.updates.getDifference(data.state.pts,data.state.date,data.state.qts,function(res){ if(!res.instanceOf('api.type.updates.DifferenceEmpty')){ //data.log('Got Diff: ',res.toPrintable()) if(res.state){ data.updateState(res.state) } if(res.chats) for(c in res.chats.list) data.addGroup(res.chats.list[c]) if(res.users) for(c in res.users.list) data.addUser(res.users.list[c]) if(res.new_messages){ res.new_messages.list.forEach(function(msg){ data.appendMsg(msg,undefined,false,false) }) } data.rebuildChatList() } setTimeout(data.downloadUpdates,1000) }) } // Get message history with given name in the given box // BROKEN, need to be rethinked data.getMessages = function(name,box){ if(!data.connected){ return // data.log('Uh cant get messages cuz not connected.....') } if(data.downloadingMessages == true) return //log('Name to obj:',name) var obj = data.nameToObj(name) if(!obj || !obj.id){ return //data.log("Can't get messages",obj,obj.id,obj.title) } var type = obj.title?'group':'user' var peer = data.idToPeer(obj.id,type) //box.add('Downloading message history for '+name) if(!peer) return log('Could not find peer:',name) data.downloadingMessages = true var oldnlines = box.getLines().length data.client.messages.getHistory(peer,0,obj.oldest_message||0,10,function(res){ //log(res.toPrintable()) //log('Got history for: '+getName(peer.user_id||peer.chat_id,peer.chat_id?'group':'user')) if(!res.messages){ return box.add(res.toPrintable()) } res.messages.list.sort(function(msg1,msg2){ return msg1.date - msg2.date }) res.messages.list.reverse() res.messages.list.forEach(function(msg){ data.appendMsg(msg,undefined,false,true) }) if(oldnlines == 0) box.setScrollPerc(100) //box.add(obj.oldest_message) data.downloadingMessages = false }) } data.appendToUserBox = function(msg,context){ var goesto if(context.messages.list.length > 0){ if(context.messages.list[0].to_id.chat_id){ // Group message //data.log('Chose',data.getName(context.messages.list[0].to_id.chat_id,'group')) goesto = data.getMsgBox(data.getName(context.messages.list[0].to_id.chat_id)) } } if(goesto === undefined){ if(context.users.list[0].user_id == data.user.id){ goesto = data.getMsgBox(data.getName(context.users.list[1].id,'user')) } else{ goesto = data.getMsgBox(data.getName(context.users.list[0].id,'user')) } } data.appendMsg(msg,goesto,true) } // Writes given telegram.link "message" object to given boxId data.appendMsg = function(msg,toBoxId,bare,prepend){ var box,param,obj if(toBoxId != undefined){ box = toBoxId } else { if(msg.to_id.chat_id != undefined){ // Is a group param = data.getName(msg.to_id.chat_id,'group') obj = data.groups[msg.to_id.chat_id] } else if(msg.from_id === msg.to_id.user_id || msg.from_id != data.user.id){ param = data.getName(msg.from_id,'user') obj = data.contacts[msg.from_id] } else if(msg.to_id.user_id != undefined && msg.to_id.user_id != data.user.id) { // don't forget dat .user_id! don't need it in from_id... param = data.getName(msg.to_id.user_id,'user') obj = data.contacts[msg.to_id.user_id] } // Increase unread count if necessary if(data.selectedWindow != param || data.msgBox[param] === undefined){ if(!obj.toread) obj.toread = 1 else obj.toread++ } // Update oldest message reference if(!obj.oldest_message || parseInt(obj.oldest_message) > parseInt(msg.id)) obj.oldest_message = parseInt(msg.id) box = data.getMsgBox(param) } if(bare) box.add(msg) else { var id = msg.from_id var date = moment.unix(msg.date).format('DD-MM-YYYY H:mm') name = data.getName(id,'user') var txt = (name || id)+' {|} {grey-fg}'+date+'{/grey-fg}\n' if(msg.media){ if(msg.media.photo) txt += '{grey-fg}>>>{/grey-fg} (Photo)' else if(msg.media.audio) txt += "{grey-fg}>>>{/grey-fg} (Audio Message) "+msg.media.audio.duration+" seconds" else if(!msg.message) txt += "{grey-fg}>>>{/grey-fg} (Unsupported Message)" } if(msg.message) txt += '{grey-fg}>{/grey-fg} '+msg.message if(prepend) box.prepend(txt) else box.add(txt) } return box } // - Entry Point - // Load authKey and userdata from disk, then act depending on outcome data.screen.render() data.log('Loading files...') fs.exists(data.keyFile,function(exists){ if(exists){ //log('Authorization Key found') fs.readFile(data.keyFile,function(err,content){ if(err) data.log('Error while reading key:',err) else { data.app.authKey = data.telegramLink.retrieveAuthKey(content,'password') // yeah sorry just testing data.log('Authorization Key found') fs.readFile(data.userFile,function(err,res){ if(err) data.log("FATAL: couldn't read user_data.json") else { try { data.user = JSON.parse(res) data.log('Welcome',data.getName(data.user.id,'user')) } catch (e) { data.log("FATAL: user data corrupted:",e) } data.connect() } }) } }) } else { data.connect() } })