├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── bin └── imsg ├── imsg.gemspec └── lib ├── applescript ├── sendToBuddy.scpt └── sendToChat.scpt ├── imsg.rb ├── imsg └── version.rb └── model ├── chat.rb └── participant.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | coverage 6 | InstalledFiles 7 | lib/bundler/man 8 | pkg 9 | rdoc 10 | spec/reports 11 | test/tmp 12 | test/version_tmp 13 | tmp 14 | .DS_Store 15 | 16 | # YARD artifacts 17 | .yardoc 18 | _yardoc 19 | doc/ 20 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in imsg.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | imsg (0.0.9) 5 | rb-appscript 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | rake (10.1.1) 11 | rb-appscript (0.6.1) 12 | 13 | PLATFORMS 14 | ruby 15 | 16 | DEPENDENCIES 17 | bundler (~> 1.5) 18 | imsg! 19 | rake 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Christian Sampaio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imsg 2 | 3 | Tired of getting off your terminal screen to answer those dickhead friends of yours? 4 | Now you can curse them right from the terminal! 5 | 6 | ## Installation 7 | 8 | It is easy as: 9 | 10 | ```bash 11 | $ gem install imsg 12 | ``` 13 | 14 | ## Usage 15 | 16 | ```bash 17 | $ imsg HELLOOO FROM TERMINAL 18 | ``` 19 | 20 | Then select a number corresponding to the person you wish to message 21 | 22 | To which chat you wanna send your message? 23 | (You can choose a number or type a buddy name/email) 24 | 1 - Christian Sampaio 25 | 2 - Linus Torvalds 26 | 3 - Tim Berners Lee 27 | 4 - Steve Wozniak 28 | 5 - Sergey Brin 29 | 6 - Larry Page 30 | ```bash 31 | $ 4 32 | ``` 33 | 34 | ## Requirements 35 | Mac OS X (will not work on other unix/linux) 36 | 37 | 38 | ## Common problems 39 | ### Using special characters: 40 | If you wanna use special characters like parentheses, brackets or quotes you need to escape it. i.e.: 41 | ```bash 42 | $ imsg HELLOOO FROM TERMINAL \(ESCAPIIING\) 43 | ``` 44 | or 45 | ```bash 46 | $ imsg "HELLOOO FROM TERMINAL (ESCAPIIING)" 47 | ``` 48 | 49 | ### Not having write permissions: 50 | 51 | If you don't have write access to your Ruby folder: 52 | 53 | ```bash 54 | $ sudo gem install imsg 55 | ``` 56 | 57 | 58 | ## Contributing 59 | 60 | 1. Fork it ( http://github.com/chrisfsampaio/imsg/fork ) 61 | 2. Create your feature branch (`git checkout -b my-new-feature`) 62 | 3. Commit your changes (`git commit -am 'Add some feature'`) 63 | 4. Push to the branch (`git push origin my-new-feature`) 64 | 5. Create new Pull Request 65 | 66 | ## Contact 67 | christian.fsampaio@gmail.com 68 | http://chrisfsampaio.github.io 69 | 70 | 71 | # <3 72 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /bin/imsg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'imsg' 3 | 4 | def interactWithUser 5 | # Gets the message and concatenate it into a string 6 | str = "" 7 | ARGV.each do |value| 8 | str +=value+" " 9 | end 10 | str = str.chomp(' '); 11 | ARGV.clear 12 | STDOUT.flush 13 | 14 | # handles user message 15 | ImsgHandler.ask_for_buddy_with_msg str 16 | end 17 | 18 | 19 | # Control+C trick in order to get out of exit() signal gracefully 20 | trap("SIGINT") { throw :ctrl_c } 21 | catch :ctrl_c do 22 | begin 23 | interactWithUser 24 | rescue Exception 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /imsg.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'imsg/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "imsg" 8 | spec.version = Imsg::VERSION 9 | spec.authors = ["Christian Sampaio"] 10 | spec.email = ["christian.fsampaio@gmail.com"] 11 | spec.date = '2014-02-11' 12 | spec.summary = "Chat using iMessage on your terminal!" 13 | spec.description = "Tired of getting off your terminal screen to answer that dickheads friends of yours? You can curse them right on the terminal now!" 14 | spec.homepage = 'https://github.com/chrisfsampaio/imsg' 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0") 18 | spec.executables << 'imsg' 19 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.5" 23 | spec.add_development_dependency "rake" 24 | spec.add_runtime_dependency "rb-appscript" 25 | end 26 | -------------------------------------------------------------------------------- /lib/applescript/sendToBuddy.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisfsampaio/imsg/1fc302d4524c3dc15667192ef5a2e4f32ce62d6e/lib/applescript/sendToBuddy.scpt -------------------------------------------------------------------------------- /lib/applescript/sendToChat.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisfsampaio/imsg/1fc302d4524c3dc15667192ef5a2e4f32ce62d6e/lib/applescript/sendToChat.scpt -------------------------------------------------------------------------------- /lib/imsg.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'imsg/version' 3 | require 'model/chat' 4 | 5 | module ImsgHandler 6 | CHAT_DISPLAY_LIMIT = 15 7 | 8 | def self.display_chats(chats) 9 | chats.first(CHAT_DISPLAY_LIMIT).map.with_index{ |x, i| "\e[1;32m#{i + 1} \e[1;31m- \e[1;36m#{x.to_s}\e[0m"}.join("\n") 10 | end 11 | 12 | def self.sort_by_updated(chats) 13 | chats.sort{ |a, b| b.updated <=> a.updated } 14 | end 15 | 16 | # Check if a String is a integer number 17 | def self.is_i?(str) 18 | str =~ /\A\d+\z/ 19 | end 20 | 21 | # Calls Applescript in order to trigger an iMessage message to a buddy 22 | # The buddy parameter accepts a String with either a chat number or a Buddy name 23 | def self.send_message message, buddy, chat 24 | script_path = File.expand_path('../applescript', __FILE__) 25 | if (chat) 26 | puts "\e[0mSending \e[1;32m\"#{message}\"\e[0m to chat with \e[1;36m\"#{chat.to_s}\"\e[0m" 27 | `osascript #{script_path}/sendToChat.scpt \"#{message}\" \"#{buddy}\"` 28 | else 29 | puts "\e[0mSending \e[1;32m\"#{message}\"\e[0m to buddy \e[1;36m\"#{buddy}\"\e[0m" 30 | `osascript #{script_path}/sendToBuddy.scpt \"#{message}\" \"#{buddy}\"` 31 | end 32 | end 33 | 34 | # Shows the chat list along with their participants 35 | def self.ask_for_buddy_with_msg msg 36 | chats = sort_by_updated(Chat.fetch_all) 37 | puts "\nTo whom would you like to send your message?" 38 | puts "(You can choose a number or type a buddy name/email)\n\n" 39 | puts display_chats(chats) + "\e[1;35m" 40 | response = gets.chomp 41 | chat = is_i?(response) ? chats[response.to_i - 1] : nil 42 | # Gets the last recipient if no chat/user was selected 43 | no_user = true if (!chat) && (!response || response.length <= 0) 44 | chat = chats.first if no_user 45 | 46 | response = chat ? chat.chat_number.to_s : response 47 | 48 | send_message(msg, response, chat) 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/imsg/version.rb: -------------------------------------------------------------------------------- 1 | module Imsg 2 | VERSION = "0.0.9" 3 | end 4 | -------------------------------------------------------------------------------- /lib/model/chat.rb: -------------------------------------------------------------------------------- 1 | require 'appscript' 2 | require 'model/participant' 3 | 4 | class Chat 5 | attr_accessor :chat_number, :updated, :participants 6 | 7 | def initialize(chat_number, updated, participants) 8 | self.chat_number = chat_number 9 | self.updated = updated 10 | self.participants = participants 11 | end 12 | 13 | def to_s 14 | participants.map(&:name).join(", ") 15 | end 16 | 17 | def self.fetch_all 18 | ascript_chats.map.with_index(1){ |chat, i| from_ascript_chat(chat, i) } 19 | end 20 | 21 | def self.ascript_chats 22 | Appscript.app("Messages").chats.get() 23 | end 24 | 25 | def self.from_ascript_chat(chat, chat_number) 26 | new(chat_number, chat.updated.get(), participants_from_ascript_chat(chat)) 27 | end 28 | 29 | def self.participants_from_ascript_chat(chat) 30 | chat.participants.get().map do |participant| 31 | Participant.from_ascript_participant(participant) 32 | end 33 | end 34 | end -------------------------------------------------------------------------------- /lib/model/participant.rb: -------------------------------------------------------------------------------- 1 | class Participant 2 | attr_accessor :name 3 | 4 | def initialize(name) 5 | self.name = name 6 | end 7 | 8 | def self.from_ascript_participant(ascript_participant) 9 | self.new(ascript_participant.name.get()) 10 | end 11 | end --------------------------------------------------------------------------------