├── BeautifulSoup-3.2.1 ├── BeautifulSoup.py ├── BeautifulSoup.pyc ├── BeautifulSoupTests.py ├── BeautifulSoupTests.pyc ├── PKG-INFO ├── build │ └── lib │ │ ├── BeautifulSoup.py │ │ └── BeautifulSoupTests.py └── setup.py ├── README.md ├── assets ├── barbosa │ ├── images │ │ ├── applet-drag-grip.png │ │ ├── device-drag-grip.png │ │ ├── flowline-bg.png │ │ ├── main-context-menu-bg.png │ │ ├── quick-call-popup-button-bg.png │ │ ├── quick-sms-send-button-bg.png │ │ └── user-drag-grip.png │ └── style.css ├── default │ ├── images │ │ ├── add-button-bg.png │ │ ├── applet-drag-grip.png │ │ ├── assign-owner-button-bg.png │ │ ├── button-bg.png │ │ ├── call-button-bg.png │ │ ├── device-drag-grip.png │ │ ├── dropdown-select-button-bg.png │ │ ├── main-context-menu-bg.png │ │ ├── nav-title-bg.png │ │ ├── normal-button-bg.png │ │ ├── play-pause-stop-bg.png │ │ ├── quick-call-button-bg.png │ │ ├── quick-call-popup-button-bg.png │ │ ├── quick-sms-button-bg.png │ │ ├── quick-sms-popup-button-bg.png │ │ ├── quick-sms-send-button-bg.png │ │ ├── sms-button-bg.png │ │ ├── submit-button-bg.png │ │ └── user-drag-grip.png │ └── style.css ├── fa │ ├── css │ │ ├── font-awesome-animation.min.css │ │ ├── font-awesome.css │ │ └── font-awesome.min.css │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── less │ │ ├── animated.less │ │ ├── bordered-pulled.less │ │ ├── core.less │ │ ├── fixed-width.less │ │ ├── font-awesome.less │ │ ├── icons.less │ │ ├── larger.less │ │ ├── list.less │ │ ├── mixins.less │ │ ├── path.less │ │ ├── rotated-flipped.less │ │ ├── screen-reader.less │ │ ├── stacked.less │ │ └── variables.less │ └── scss │ │ ├── _animated.scss │ │ ├── _bordered-pulled.scss │ │ ├── _core.scss │ │ ├── _fixed-width.scss │ │ ├── _icons.scss │ │ ├── _larger.scss │ │ ├── _list.scss │ │ ├── _mixins.scss │ │ ├── _path.scss │ │ ├── _rotated-flipped.scss │ │ ├── _screen-reader.scss │ │ ├── _stacked.scss │ │ ├── _variables.scss │ │ └── font-awesome.scss ├── global.css ├── global.js ├── griffin │ ├── images │ │ ├── assign-owner-button-bg.png │ │ ├── button-bg.png │ │ ├── call-button-bg.png │ │ ├── dropdown-select-button-bg.png │ │ ├── flowline-nav-arrows-sprite.png │ │ ├── main-context-menu-bg.png │ │ ├── normal-button-bg.png │ │ ├── play-pause-stop-bg.png │ │ ├── quick-call-button-bg.png │ │ ├── quick-call-popup-button-bg.png │ │ ├── quick-sms-button-bg.png │ │ ├── quick-sms-popup-button-bg.png │ │ ├── sms-button-bg.png │ │ └── submit-button-bg.png │ └── style.css ├── images │ ├── action-icons-mini-sprite.png │ ├── action-icons-sprite.png │ ├── ajax-loader-circle-dark.gif │ ├── ajax-loader-circle.gif │ ├── ajax-loader.gif │ ├── applet-drag-grip.png │ ├── applet-icons-sprite.png │ ├── assign-owner-button-bg.png │ ├── button-bg.png │ ├── call-button-bg.png │ ├── client-first-run-arrow.png │ ├── client-first-run-bg.png │ ├── device-drag-grip.png │ ├── devices-icon.png │ ├── dropdown-select-button-bg.png │ ├── email-button-bg.png │ ├── flowline-nav-arrows-sprite.png │ ├── flows-icon.png │ ├── form-input-text-150.png │ ├── form-input-text-200.png │ ├── form-input-text-300.png │ ├── form-input-text-50.png │ ├── form-input-text-600.png │ ├── icon.png │ ├── info-banner-icon.png │ ├── main-context-menu-bg.png │ ├── message-status-icon-bg.png │ ├── messages-icon.png │ ├── mic_big.png │ ├── normal-button-bg.png │ ├── numbers-icon.png │ ├── overlay.png │ ├── play-pause-stop-bg.png │ ├── quick-call-button-bg.png │ ├── quick-call-popup-button-bg.png │ ├── quick-sms-button-bg.png │ ├── quick-sms-popup-button-bg.png │ ├── remove-user.png │ ├── sms-button-bg.png │ ├── standard-icons-sprite.png │ ├── submit-button-bg.png │ ├── timepicker-add.png │ ├── timepicker-remove.png │ ├── toggle-arrow-16.png │ ├── user-drag-grip.png │ ├── user-group-icon.png │ ├── user-group-picker-group-icon.png │ ├── user-group-picker-person-icon.png │ ├── user-group-utilities.png │ ├── user-icon.png │ ├── user-list-status-icon-sprite.png │ └── voicemail-icon.png ├── jquery-ui-1.8.14.custom.min.js ├── jquery.min.js ├── mandala │ ├── images │ │ ├── assign-owner-button-bg.png │ │ ├── button-bg.png │ │ ├── call-button-bg.png │ │ ├── dropdown-select-button-bg.png │ │ ├── main-context-menu-bg.png │ │ ├── normal-button-bg.png │ │ ├── play-message-button-bg.png │ │ ├── play-pause-stop-bg.png │ │ ├── quick-call-button-bg.png │ │ ├── quick-call-popup-button-bg.png │ │ ├── quick-sms-button-bg.png │ │ ├── quick-sms-popup-button-bg.png │ │ ├── quick-sms-send-button-bg.png │ │ ├── sms-button-bg.png │ │ ├── submit-button-bg.png │ │ └── user-drag-grip.png │ └── style.css ├── mediaelement-and-player.min.js ├── mediaelement-flash-audio.swf ├── mediaelementplayer.min.css ├── mejs-controls.png └── mejs-controls.svg ├── googlevoice.php ├── gvactions.php ├── gvactions.py ├── gvaddnote.py ├── gvcall.py ├── gvcallcancel.py ├── gvconfig.php ├── gvdashboard.php ├── gvdetails.php ├── gvdetails.py ├── gvhistory.py ├── gvmessages.py ├── gvpagination.php ├── gvping.php ├── gvrecorded-mp3.py ├── gvsendsms.py ├── gvsettingcheck.php ├── gvsettingcheck.py ├── gvvoicemail-mp3.py ├── header.php ├── index.php ├── pygooglevoice ├── LICENSE.txt ├── README ├── README.rst ├── bin │ ├── asterisk-gvoice-setup │ ├── gvi │ └── gvoice ├── build │ └── lib │ │ └── googlevoice │ │ ├── __init__.py │ │ ├── conf.py │ │ ├── settings.py │ │ ├── tests.py │ │ ├── util.py │ │ └── voice.py ├── docs │ ├── Makefile │ ├── api.txt │ ├── changelog.txt │ ├── conf.py │ ├── config.txt │ ├── examples.txt │ ├── index.txt │ ├── install.txt │ └── scripts.txt ├── examples │ ├── call.py │ ├── delete.py │ ├── download-mp3.py │ ├── folders.py │ ├── parse_sms.py │ ├── phones.py │ ├── search.py │ ├── settings.py │ ├── sms.py │ └── voicemail.py ├── googlevoice │ ├── __init__.py │ ├── conf.py │ ├── settings.py │ ├── tests.py │ ├── util.py │ └── voice.py └── setup.py ├── screenshoot1.jpg ├── screenshoot2.jpg └── setup.sh /BeautifulSoup-3.2.1/BeautifulSoup.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/BeautifulSoup-3.2.1/BeautifulSoup.pyc -------------------------------------------------------------------------------- /BeautifulSoup-3.2.1/BeautifulSoupTests.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/BeautifulSoup-3.2.1/BeautifulSoupTests.pyc -------------------------------------------------------------------------------- /BeautifulSoup-3.2.1/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: BeautifulSoup 3 | Version: 3.2.1 4 | Summary: HTML/XML parser for quick-turnaround applications like screen-scraping. 5 | Home-page: http://www.crummy.com/software/BeautifulSoup/ 6 | Author: Leonard Richardson 7 | Author-email: leonardr@segfault.org 8 | License: BSD 9 | Download-URL: http://www.crummy.com/software/BeautifulSoup/download/ 10 | Description: Beautiful Soup parses arbitrarily invalid SGML and provides a variety of methods and Pythonic idioms for iterating and searching the parse tree. 11 | Platform: UNKNOWN 12 | Classifier: Development Status :: 5 - Production/Stable 13 | Classifier: Intended Audience :: Developers 14 | Classifier: License :: OSI Approved :: Python Software Foundation License 15 | Classifier: Programming Language :: Python 16 | Classifier: Topic :: Text Processing :: Markup :: HTML 17 | Classifier: Topic :: Text Processing :: Markup :: XML 18 | Classifier: Topic :: Text Processing :: Markup :: SGML 19 | Classifier: Topic :: Software Development :: Libraries :: Python Modules 20 | -------------------------------------------------------------------------------- /BeautifulSoup-3.2.1/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | import unittest 3 | import warnings 4 | warnings.filterwarnings("ignore", "Unknown distribution option") 5 | 6 | import sys 7 | # patch distutils if it can't cope with the "classifiers" keyword 8 | if sys.version < '2.2.3': 9 | from distutils.dist import DistributionMetadata 10 | DistributionMetadata.classifiers = None 11 | DistributionMetadata.download_url = None 12 | 13 | from BeautifulSoup import __version__ 14 | 15 | #Make sure all the tests complete. 16 | import BeautifulSoupTests 17 | loader = unittest.TestLoader() 18 | result = unittest.TestResult() 19 | suite = loader.loadTestsFromModule(BeautifulSoupTests) 20 | suite.run(result) 21 | if not result.wasSuccessful(): 22 | print "Unit tests have failed!" 23 | for l in result.errors, result.failures: 24 | for case, error in l: 25 | print "-" * 80 26 | desc = case.shortDescription() 27 | if desc: 28 | print desc 29 | print error 30 | print '''If you see an error like: "'ascii' codec can't encode character...", see\nthe Beautiful Soup documentation:\n http://www.crummy.com/software/BeautifulSoup/documentation.html#Why%20can't%20Beautiful%20Soup%20print%20out%20the%20non-ASCII%20characters%20I%20gave%20it?''' 31 | print "This might or might not be a problem depending on what you plan to do with\nBeautiful Soup." 32 | if sys.argv[1] == 'sdist': 33 | print 34 | print "I'm not going to make a source distribution since the tests don't pass." 35 | sys.exit(1) 36 | 37 | setup(name="BeautifulSoup", 38 | version=__version__, 39 | py_modules=['BeautifulSoup', 'BeautifulSoupTests'], 40 | description="HTML/XML parser for quick-turnaround applications like screen-scraping.", 41 | author="Leonard Richardson", 42 | author_email = "leonardr@segfault.org", 43 | long_description="""Beautiful Soup parses arbitrarily invalid SGML and provides a variety of methods and Pythonic idioms for iterating and searching the parse tree.""", 44 | classifiers=["Development Status :: 5 - Production/Stable", 45 | "Intended Audience :: Developers", 46 | "License :: OSI Approved :: Python Software Foundation License", 47 | "Programming Language :: Python", 48 | "Topic :: Text Processing :: Markup :: HTML", 49 | "Topic :: Text Processing :: Markup :: XML", 50 | "Topic :: Text Processing :: Markup :: SGML", 51 | "Topic :: Software Development :: Libraries :: Python Modules", 52 | ], 53 | url="http://www.crummy.com/software/BeautifulSoup/", 54 | license="BSD", 55 | download_url="http://www.crummy.com/software/BeautifulSoup/download/" 56 | ) 57 | 58 | # Send announce to: 59 | # python-announce@python.org 60 | # python-list@python.org 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # minigooglevoice - Addon App for Admin's 2 | Make calls, send SMS and reply directly from your backen help or support desk website. 3 | 4 | This Application is a mixure of Python and PHP requiring: 5 | 1. pygooglevoice from https://github.com/EspaceNetworks/pygooglevoice 6 | 2. BeautifulSoup3.2.1 from https://pypi.python.org/pypi/BeautifulSoup/3.2.1 7 | 3. mediaelement from https://github.com/mediaelement/mediaelement 8 | 4. Font-Awesome from https://github.com/FortAwesome/Font-Awesome 9 | 5. openvbx theme layout pulled from https://github.com/twilio/OpenVBX/network 10 | 6. jquery 11 | 12 | ![Alt text](/screenshoot1.jpg?raw=true "Setting Page") 13 | ![Alt text](/screenshoot2.jpg?raw=true "Dashboard Page") 14 | -------------------------------------------------------------------------------- /assets/barbosa/images/applet-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/barbosa/images/applet-drag-grip.png -------------------------------------------------------------------------------- /assets/barbosa/images/device-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/barbosa/images/device-drag-grip.png -------------------------------------------------------------------------------- /assets/barbosa/images/flowline-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/barbosa/images/flowline-bg.png -------------------------------------------------------------------------------- /assets/barbosa/images/main-context-menu-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/barbosa/images/main-context-menu-bg.png -------------------------------------------------------------------------------- /assets/barbosa/images/quick-call-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/barbosa/images/quick-call-popup-button-bg.png -------------------------------------------------------------------------------- /assets/barbosa/images/quick-sms-send-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/barbosa/images/quick-sms-send-button-bg.png -------------------------------------------------------------------------------- /assets/barbosa/images/user-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/barbosa/images/user-drag-grip.png -------------------------------------------------------------------------------- /assets/barbosa/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Template Name: Barbosa 3 | */ 4 | 5 | /* Links */ 6 | 7 | .barbosa-theme a:link { 8 | color: #368FC9; 9 | } 10 | 11 | .barbosa-theme a:visited { 12 | color: #368FC9; 13 | } 14 | 15 | .barbosa-theme a:hover { 16 | color: #40A4D9; 17 | } 18 | 19 | .barbosa-theme a:active { 20 | color: #333; 21 | } 22 | 23 | 24 | #context-menu { 25 | padding: 5px; 26 | background: #E37E33 url(images/main-context-menu-bg.png) repeat-x top left; 27 | border-bottom: 1px solid #FFF; 28 | overflow: auto; 29 | -moz-border-radius-topleft: 4px; 30 | -moz-border-radius-topright: 4px; 31 | -webkit-border-radius-topleft: 4px; 32 | -webkit-border-radius-topright: 4px; 33 | } 34 | 35 | 36 | 37 | /* Main Navigation */ 38 | 39 | #main-nav .nav-item a { 40 | display: block; 41 | padding: 6px 5px 6px 10px; 42 | font-size: 14px; 43 | text-decoration: none; 44 | background-color: #FFF; 45 | border: none; 46 | overflow: auto; 47 | } 48 | 49 | #main-nav .nav-item a:hover { 50 | color: #40A4D9; 51 | } 52 | 53 | #main-nav .selected a, 54 | #main-nav .selected a:hover { 55 | width: 166px; 56 | font-size: 14px; 57 | font-weight: bold; 58 | color: #FFF1C3; 59 | background-color: #333; 60 | } 61 | 62 | 63 | 64 | .items-grid .quick-call-popup .call { 65 | display: block; 66 | height: 28px; 67 | line-height: 28px; 68 | width: 42px; 69 | padding-left: 24px; 70 | font-size: 16px; 71 | font-weight: bold; 72 | color: #FFF; 73 | text-decoration: none; 74 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 75 | } 76 | 77 | .items-grid .quick-sms-popup .send-button { 78 | height: 28px; 79 | width: 80px; 80 | margin-left: 10px; 81 | padding-left: 24px; 82 | font-size: 16px; 83 | font-weight: bold; 84 | color: #FFF; 85 | background: url(images/quick-sms-send-button-bg.png) no-repeat center center; 86 | } 87 | 88 | 89 | 90 | /* Message Details*/ 91 | 92 | .message-details-header .quick-call-popup .call { 93 | display: block; 94 | height: 28px; 95 | line-height: 28px; 96 | width: 42px; 97 | padding-left: 20px; 98 | font-size: 16px; 99 | font-weight: bold; 100 | color: #FFF; 101 | text-decoration: none; 102 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 103 | } 104 | 105 | 106 | 107 | /* Admin */ 108 | 109 | #user-container .user { 110 | display: inline-block; 111 | width: 221px; 112 | margin: 0 10px 10px 0; 113 | padding: 20px 10px 10px 10px; 114 | background: #FFF url(images/user-drag-grip.png) no-repeat center 2px; 115 | cursor: move; 116 | overflow: hidden; 117 | border: 1px solid #777; 118 | -moz-border-radius: 4px; 119 | -webkit-border-radius: 4px; 120 | } 121 | 122 | 123 | a { 124 | font-style: none; 125 | text-decoration: none; 126 | border: none; 127 | } 128 | a:hover { 129 | text-decoration: none; 130 | border: none; 131 | } 132 | 133 | a:button { 134 | text-decoration: none; 135 | border: none; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /assets/default/images/add-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/add-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/applet-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/applet-drag-grip.png -------------------------------------------------------------------------------- /assets/default/images/assign-owner-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/assign-owner-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/button-bg.png -------------------------------------------------------------------------------- /assets/default/images/call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/call-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/device-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/device-drag-grip.png -------------------------------------------------------------------------------- /assets/default/images/dropdown-select-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/dropdown-select-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/main-context-menu-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/main-context-menu-bg.png -------------------------------------------------------------------------------- /assets/default/images/nav-title-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/nav-title-bg.png -------------------------------------------------------------------------------- /assets/default/images/normal-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/normal-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/play-pause-stop-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/play-pause-stop-bg.png -------------------------------------------------------------------------------- /assets/default/images/quick-call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/quick-call-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/quick-call-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/quick-call-popup-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/quick-sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/quick-sms-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/quick-sms-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/quick-sms-popup-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/quick-sms-send-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/quick-sms-send-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/sms-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/submit-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/submit-button-bg.png -------------------------------------------------------------------------------- /assets/default/images/user-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/default/images/user-drag-grip.png -------------------------------------------------------------------------------- /assets/default/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Template Name: Default 3 | */ 4 | 5 | 6 | 7 | /* Links */ 8 | 9 | .default-theme a:link { 10 | color: #333; 11 | } 12 | 13 | .default-theme a:visited { 14 | color: #777; 15 | } 16 | 17 | .default-theme a:hover { 18 | color: #000; 19 | } 20 | 21 | .default-theme a:active { 22 | color: #09F; 23 | } 24 | 25 | #util-menu .util-item a { 26 | display: block; 27 | float: left; 28 | padding: 4px 6px; 29 | margin-left: 15px; 30 | color: #4E9E29; 31 | background-color: #FFF; 32 | } 33 | 34 | #util-menu .util-item .username { 35 | color: #777; 36 | } 37 | 38 | 39 | 40 | #context-menu { 41 | padding: 5px; 42 | background: #666 url(images/main-context-menu-bg.png) repeat-x left bottom; 43 | border-bottom: 1px solid #FFF; 44 | overflow: auto; 45 | -moz-border-radius-topleft: 4px; 46 | -moz-border-radius-topright: 4px; 47 | -webkit-border-radius-topleft: 4px; 48 | -webkit-border-radius-topright: 4px; 49 | } 50 | 51 | #main-nav .nav-title { 52 | padding: 4px 10px; 53 | font-size: 11px; 54 | font-weight: bold; 55 | color: #8BC8E9; 56 | text-transform: uppercase; 57 | background: #316480 url(images/nav-title-bg.png) repeat-x left top; 58 | border-bottom: 1px solid #316480; 59 | } 60 | 61 | #main-nav .nav-item a { 62 | display: block; 63 | padding: 6px 5px 6px 10px; 64 | font-size: 14px; 65 | color: #FFF; 66 | text-decoration: none; 67 | background-color: #869BA6; 68 | border-bottom: 1px solid #FFF; 69 | } 70 | 71 | #main-nav .nav-item a:hover { 72 | background-color: #6DA0BE; 73 | } 74 | 75 | #main-nav .selected a, 76 | #main-nav .selected a:hover { 77 | width: 166px; 78 | font-size: 14px; 79 | font-weight: bold; 80 | color: #F7ECB7; 81 | background-color: #333; 82 | } 83 | 84 | 85 | .items-grid .unread .phone-number { 86 | color: #329FD8; 87 | } 88 | 89 | .items-grid .message-row .phone-number { 90 | color: #316480; 91 | } 92 | 93 | .items-grid .quick-call-popup .call { 94 | display: block; 95 | height: 28px; 96 | line-height: 28px; 97 | width: 42px; 98 | padding-left: 24px; 99 | font-size: 16px; 100 | font-weight: bold; 101 | color: #FFF; 102 | text-decoration: none; 103 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 104 | } 105 | 106 | .items-grid .quick-sms-popup .send-button { 107 | height: 28px; 108 | width: 80px; 109 | margin-left: 10px; 110 | padding-left: 24px; 111 | font-size: 16px; 112 | font-weight: bold; 113 | color: #FFF; 114 | background: url(images/quick-sms-popup-button-bg.png) no-repeat center center; 115 | } 116 | 117 | .pagination a:link, 118 | .pagination a:visited { 119 | color: #BBB; 120 | } 121 | 122 | .pagination a:hover { 123 | color: #FFF; 124 | } 125 | 126 | .pagination a:active { 127 | color: #FFF; 128 | } 129 | 130 | .pagination .current { 131 | color: #FFF; 132 | background-color: #333; 133 | } 134 | 135 | .ui-dialog .ui-dialog-titlebar { 136 | color: #FFF; 137 | background-color: #329FD8; 138 | } 139 | 140 | 141 | 142 | 143 | /* Message Details*/ 144 | 145 | .message-details-header .quick-call-popup .call { 146 | display: block; 147 | height: 28px; 148 | line-height: 28px; 149 | width: 42px; 150 | padding-left: 20px; 151 | font-size: 16px; 152 | font-weight: bold; 153 | color: #FFF; 154 | text-decoration: none; 155 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 156 | } 157 | 158 | 159 | 160 | /* Buttons */ 161 | 162 | button.normal-button { 163 | background: transparent url(images/normal-button-bg.png) no-repeat right -96px; 164 | } 165 | 166 | button.normal-button span { 167 | background: transparent url(images/normal-button-bg.png) no-repeat left top; 168 | color: #253C49; 169 | } 170 | 171 | button.normal-button:hover span, button.normal-button-hover span { 172 | color: #0D181E; 173 | } 174 | 175 | button.normal-button:active span, button.normal-button-active span { 176 | color: #2E5669; 177 | } 178 | 179 | 180 | button.submit-button { 181 | background: transparent url(images/submit-button-bg.png) no-repeat right -96px; 182 | } 183 | 184 | button.submit-button span { 185 | background: transparent url(images/submit-button-bg.png) no-repeat left top; 186 | color: #253C49; 187 | } 188 | 189 | button.submit-button:hover span, button.submit-button-hover span { 190 | color: #0D181E; 191 | } 192 | 193 | button.submit-button:active span, button.submit.button-active span { 194 | color: #2E5669; 195 | } 196 | 197 | button.call-button { 198 | background: transparent url(images/call-button-bg.png) no-repeat right -96px; 199 | } 200 | 201 | button.call-button span { 202 | background: transparent url(images/call-button-bg.png) no-repeat left top; 203 | color: #253C49; 204 | } 205 | 206 | button.call-button:hover span, button.call-button-hover span { 207 | color: #0D181E; 208 | } 209 | 210 | button.call-button:active span, button.call-button-active span { 211 | color: #2E5669; 212 | } 213 | 214 | button.sms-button { 215 | background: transparent url(images/sms-button-bg.png) no-repeat right -96px; 216 | } 217 | 218 | button.sms-button span { 219 | background: transparent url(images/sms-button-bg.png) no-repeat left top; 220 | color: #253C49; 221 | } 222 | 223 | button.sms-button:hover span, button.sms-button-hover span { 224 | color: #0D181E; 225 | } 226 | 227 | button.sms-button:active span, button.sms-button-active span { 228 | color: #2E5669; 229 | } 230 | 231 | .quick-call-button { 232 | background: url(images/quick-call-button-bg.png) no-repeat center top; 233 | } 234 | 235 | .quick-sms-button { 236 | background: url(images/quick-sms-button-bg.png) no-repeat center top; 237 | } 238 | 239 | 240 | .playback-button { 241 | background: url(images/play-pause-stop-bg.png) no-repeat left top; 242 | } 243 | 244 | .assign-button { 245 | background: url(images/assign-owner-button-bg.png) no-repeat right top; 246 | } 247 | 248 | 249 | 250 | a { 251 | font-style: none; 252 | text-decoration: none; 253 | border: none; 254 | } 255 | a:hover { 256 | text-decoration: none; 257 | border: none; 258 | } 259 | 260 | a:button { 261 | text-decoration: none; 262 | border: none; 263 | } 264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /assets/fa/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/fa/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /assets/fa/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/fa/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /assets/fa/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/fa/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /assets/fa/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/fa/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /assets/fa/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/fa/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /assets/fa/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /assets/fa/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /assets/fa/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /assets/fa/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /assets/fa/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /assets/fa/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /assets/fa/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /assets/fa/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | .fa-icon-rotate(@degrees, @rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 16 | -webkit-transform: rotate(@degrees); 17 | -ms-transform: rotate(@degrees); 18 | transform: rotate(@degrees); 19 | } 20 | 21 | .fa-icon-flip(@horiz, @vert, @rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 23 | -webkit-transform: scale(@horiz, @vert); 24 | -ms-transform: scale(@horiz, @vert); 25 | transform: scale(@horiz, @vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | .sr-only() { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | .sr-only-focusable() { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /assets/fa/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /assets/fa/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /assets/fa/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /assets/fa/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /assets/fa/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /assets/fa/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /assets/fa/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /assets/fa/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /assets/fa/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /assets/fa/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /assets/fa/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /assets/fa/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /assets/fa/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /assets/fa/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /assets/fa/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /assets/fa/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /assets/global.js: -------------------------------------------------------------------------------- 1 | function preventDefault(e) { 2 | e.preventDefault() 3 | }; 4 | 5 | function notify(message) { 6 | var close = 'Close'; 7 | var info = ''; 8 | $('.notify').addClass('hide'); 9 | setTimeout(function() { 10 | $('.notify .message').text(message).append(info).append(close); 11 | $('.notify').removeClass('hide').fadeIn('slow'); 12 | $('.notify').delay(10000).fadeOut('slow'); 13 | }, 500); 14 | return $('.notify'); 15 | }; 16 | 17 | function gvaction(ACTIONS, ID, RETURN, TEXT){ 18 | $.post('gvactions.php', { action: ACTIONS, messageId: ID, messagenote: TEXT }, 19 | function(data) { 20 | notify(data); 21 | if (ACTIONS == 'delete'){ 22 | if (RETURN){ 23 | window.location.href = 'gvdashboard.php?command=' + RETURN; 24 | } else { 25 | window.location.href = 'gvdashboard.php'; 26 | } 27 | } 28 | }); 29 | }; 30 | 31 | 32 | jQuery.fn.buttonista = function(options) { 33 | var settings = jQuery.extend({ 34 | menu : 'ul', 35 | toggler : '.toggler' 36 | }, options); 37 | 38 | var toggleMenu = function() { 39 | $(this).parent() 40 | .children(settings.menu).toggleClass('open'); 41 | if($(this).parent().children(settings.menu).hasClass('open') && 42 | typeof settings.focus != 'undefined') 43 | { 44 | $(this).parent() 45 | .children(settings.menu).children(settings.focus).focus() 46 | } 47 | return false; 48 | }; 49 | 50 | var closeMenu = function(event) { 51 | if (event.keyCode == '27') { 52 | $(settings.menu).removeClass('open'); 53 | } 54 | }; 55 | 56 | $(window).keypress( closeMenu ); 57 | 58 | return this.each(function() { 59 | var link = $(this); 60 | link.click( toggleMenu ); 61 | 62 | var toggler = $(settings.toggler, link.parent()); 63 | toggler.click(function(event) { 64 | event.preventDefault(); 65 | 66 | link.click(); 67 | }); 68 | 69 | }); 70 | }; 71 | 72 | $(document).ready(function() { 73 | 74 | $('.caller-id-phone a').click(function() { 75 | var anchor = $(this); 76 | var popup = $(this).parents('.quick-call-popup'); 77 | if(anchor.parents('ul.caller-id-phone')) { 78 | anchor.hide() 79 | .parents('ul') 80 | .append('
  • Calling...
  • '); 81 | 82 | } else { 83 | anchor.hide() 84 | .parent() 85 | .append('
  • Calling...
  • '); 86 | } 87 | $.ajax({ 88 | url : "gvactions.php", 89 | data : { 90 | action : "callNumber", 91 | numberToCall : $('.to', popup).text() 92 | }, 93 | dataType: 'html', 94 | success : function(data) { 95 | $('.quick-call-popup .calling').remove(); 96 | $('.quick-call-popup.open').toggleClass('open'); 97 | notify(data); 98 | anchor.show(); 99 | }, 100 | type : 'POST' 101 | }); 102 | return true; 103 | }); 104 | 105 | 106 | 107 | 108 | $('.quick-sms-popup .send-button').click(function(event) { 109 | var popup = $(this).parents('.quick-sms-popup'); 110 | $('.sending-sms-loader').show(); 111 | $.ajax({ 112 | url : "gvactions.php", 113 | data : { 114 | action : "sendText", 115 | to : $('.sms-to-phone', popup).text(), 116 | content : $('input[name="content"]', popup).val() 117 | }, 118 | dataType: 'html', 119 | success : function(data) { 120 | $('.sending-sms-loader').hide(); 121 | if(!data.error) { 122 | $('textarea', popup).val(''); 123 | $(popup).hide(); 124 | notify(data); 125 | } 126 | }, 127 | error : function() { 128 | $('.sending-sms-loader').hide(); 129 | }, 130 | type : 'POST' 131 | }); 132 | event.preventDefault(); 133 | }); 134 | 135 | 136 | $('.quick-call-button').buttonista({ menu : '.quick-call-popup' }); 137 | $('.quick-sms-button').buttonista({ menu : '.quick-sms-popup', toggler : '.sms-toggler', focus: '.sms-message' }); 138 | var updateCount = function() { 139 | var length = $(this).val().length; 140 | $(this).parents('.quick-sms-popup, #reply-sms') 141 | .find('.count') 142 | .text(1600 - length); 143 | }; 144 | $('.quick-sms-popup input[name="content"]').live('keyup', updateCount); 145 | $('.quick-sms-popup input[name="content"]').keypress(); 146 | $('#reply-sms textarea').live('keyup', updateCount); 147 | $('#reply-sms textarea').live('keyup', updateCount); 148 | $('#reply-sms textarea').keypress(); 149 | $('#reply-sms .submit-button').click(function(event) { 150 | event.preventDefault(); 151 | $('#reply-sms button').prop('disabled', true); 152 | $('#reply-sms .loader').show(); 153 | $.ajax({ 154 | url : $('#reply-sms').attr('action'), 155 | data : $('#reply-sms').serializeArray(), 156 | success : function(data) { 157 | $('#reply-sms .loader').hide(); 158 | $.notify(data); 159 | $('#reply-sms textarea').val(''); 160 | $('#reply-sms .submit-button').prop('disabled', false).flicker(); 161 | window.location.href = 'gvdetails.php?messageId=' + $('#reply-sms').attr('messageId'); 162 | }, 163 | type : 'POST', 164 | dataType: 'html' 165 | }); 166 | 167 | return false; 168 | }); 169 | }); 170 | -------------------------------------------------------------------------------- /assets/griffin/images/assign-owner-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/assign-owner-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/call-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/dropdown-select-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/dropdown-select-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/flowline-nav-arrows-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/flowline-nav-arrows-sprite.png -------------------------------------------------------------------------------- /assets/griffin/images/main-context-menu-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/main-context-menu-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/normal-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/normal-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/play-pause-stop-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/play-pause-stop-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/quick-call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/quick-call-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/quick-call-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/quick-call-popup-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/quick-sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/quick-sms-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/quick-sms-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/quick-sms-popup-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/sms-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/images/submit-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/griffin/images/submit-button-bg.png -------------------------------------------------------------------------------- /assets/griffin/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: Griffin 3 | */ 4 | 5 | /* Global */ 6 | html, 7 | body, 8 | #hd, 9 | #bd, 10 | #ft { 11 | background-color: #000; 12 | } 13 | 14 | 15 | #hd { 16 | } 17 | 18 | #ft { 19 | border-top: 1px solid #222; 20 | } 21 | 22 | 23 | /* Links */ 24 | 25 | .griffin-theme a:link { 26 | color: #C00; 27 | } 28 | 29 | .griffin-theme a:visited { 30 | color: #C00; 31 | } 32 | 33 | .griffin-theme a:hover { 34 | color: #F00; 35 | } 36 | 37 | .griffin-theme a:active { 38 | color: #FFF; 39 | } 40 | 41 | 42 | #util-menu .util-item a { 43 | background: none; 44 | } 45 | 46 | #util-menu .util-item .username { 47 | color: #FFF; 48 | background-color: none; 49 | } 50 | 51 | 52 | #context-menu { 53 | padding: 5px; 54 | background-color: #B62332; 55 | border-bottom: 1px solid #000; 56 | overflow: auto; 57 | -moz-border-radius-topleft: 4px; 58 | -moz-border-radius-topright: 4px; 59 | -webkit-border-radius-topleft: 4px; 60 | -webkit-border-radius-topright: 4px; 61 | } 62 | 63 | /* Main Navigation */ 64 | 65 | #main-nav { 66 | background-color: #000; 67 | } 68 | 69 | #main-nav .nav-title { 70 | padding: 4px 10px; 71 | font-size: 11px; 72 | font-weight: bold; 73 | color: #B62332; 74 | text-transform: uppercase; 75 | background-color: #64131C; 76 | border-bottom: 1px solid #000; 77 | } 78 | 79 | #main-nav .nav-item a { 80 | display: block; 81 | padding: 6px 5px 6px 10px; 82 | font-size: 14px; 83 | color: #CCC; 84 | text-decoration: none; 85 | background-color: #1F1F1F; 86 | border-top: none; 87 | border-bottom: 1px solid #000; 88 | overflow: auto; 89 | } 90 | 91 | #main-nav .nav-item a:hover { 92 | color: #F7ECB7; 93 | background-color: #313131; 94 | } 95 | 96 | #main-nav .selected a, 97 | #main-nav .selected a:hover { 98 | width: 166px; 99 | font-size: 14px; 100 | font-weight: bold; 101 | color: #FFF; 102 | background-color: #B62332; 103 | border-bottom: 1px solid #000; 104 | } 105 | 106 | #main { 107 | background-color: #B62332; 108 | } 109 | 110 | /* Content Menu */ 111 | 112 | .content-menu { 113 | background-color: #B62332; 114 | } 115 | 116 | .content-menu .menu-item a.link-button { 117 | background: url(images/button-bg.png) no-repeat right -96px; 118 | } 119 | 120 | .content-menu .menu-item a.dropdown-select-button { 121 | background: url(images/dropdown-select-button-bg.png) no-repeat right -96px; 122 | } 123 | 124 | .content-menu .menu-item a.link-button span { 125 | color: #FFF; 126 | background: url(images/button-bg.png) no-repeat left top; 127 | } 128 | 129 | .content-menu .menu-item a.dropdown-select-button span { 130 | color: #FFF; 131 | background: url(images/dropdown-select-button-bg.png) no-repeat left top; 132 | } 133 | 134 | 135 | 136 | /* Content Items Grid */ 137 | 138 | .items-grid { 139 | background-color: #1F1F1F; 140 | border: 3px solid #64131C; 141 | } 142 | 143 | .items-grid .log-head-row th { 144 | background-color: #000; 145 | border-bottom: 1px solid #64131C; 146 | } 147 | 148 | .items-grid .log-row td { 149 | background-color: #000; 150 | border-bottom: 1px solid #64131C; 151 | } 152 | 153 | .items-grid .message-row td { 154 | color: #CCC; 155 | background-color: #1F1F1F; 156 | border-bottom: 1px solid #64131C; 157 | } 158 | 159 | .items-grid .unread td { 160 | color: #EEE; 161 | background-color: #141414; 162 | } 163 | 164 | .items-grid .hover td { 165 | background-color: #292929; 166 | } 167 | 168 | .items-grid .mousedown td { 169 | background-color: #333333; 170 | } 171 | 172 | .items-grid .clicked td { 173 | background-color: #333333; 174 | } 175 | 176 | .items-grid .checked td { 177 | background-color: #292929; 178 | } 179 | 180 | .items-grid .unread .phone-number { 181 | color: #CCC; 182 | } 183 | 184 | .items-grid .message-row .phone-number { 185 | color: #666; 186 | } 187 | 188 | 189 | .items-grid .quick-call-popup { 190 | background-color: #000; 191 | } 192 | 193 | 194 | .items-grid .quick-call-popup .call { 195 | display: block; 196 | height: 28px; 197 | line-height: 28px; 198 | width: 42px; 199 | padding-left: 24px; 200 | font-size: 16px; 201 | font-weight: bold; 202 | color: #FFF; 203 | text-decoration: none; 204 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 205 | } 206 | 207 | .items-grid .quick-sms-popup .send-button { 208 | height: 28px; 209 | width: 80px; 210 | margin-left: 10px; 211 | padding-left: 24px; 212 | font-size: 16px; 213 | font-weight: bold; 214 | color: #FFF; 215 | background: url(images/quick-sms-popup-button-bg.png) no-repeat center center; 216 | } 217 | 218 | 219 | 220 | /* Message Details*/ 221 | 222 | .message-details-header, 223 | .message-details-playback { 224 | border-bottom: 1px solid #222; 225 | } 226 | 227 | .message-details-transcript { 228 | border-bottom: none; 229 | } 230 | 231 | .message-details-header .quick-call-popup .call { 232 | display: block; 233 | height: 28px; 234 | line-height: 28px; 235 | width: 42px; 236 | padding-left: 24px; 237 | font-size: 16px; 238 | font-weight: bold; 239 | color: #FFF; 240 | text-decoration: none; 241 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 242 | } 243 | 244 | .message-details-notes #message-details-notes-list { 245 | border: 1px solid #222; 246 | } 247 | 248 | .message-details-notes #message-details-notes-list .note { 249 | border: 1px solid #222; 250 | } 251 | 252 | 253 | 254 | /* Admin */ 255 | 256 | #user-container .user { 257 | display: inline-block; 258 | width: 221px; 259 | margin: 0 10px 10px 0; 260 | padding: 20px 10px 10px 10px; 261 | background: #FFF url(images/user-drag-grip.png) no-repeat center 2px; 262 | cursor: move; 263 | overflow: hidden; 264 | border: 1px solid #777; 265 | -moz-border-radius: 4px; 266 | -webkit-border-radius: 4px; 267 | } 268 | 269 | 270 | /* Buttons */ 271 | 272 | button.normal-button { 273 | background: transparent url(images/normal-button-bg.png) no-repeat right -96px; 274 | } 275 | 276 | button.normal-button span { 277 | background: transparent url(images/normal-button-bg.png) no-repeat left top; 278 | color: #F9EDD5; 279 | } 280 | 281 | button.normal-button:hover span, button.normal-button-hover span { 282 | color: #FFF 283 | } 284 | 285 | button.normal-button:active span, button.normal-button-active span { 286 | color: #FFF; 287 | } 288 | 289 | 290 | button.submit-button { 291 | background: transparent url(images/submit-button-bg.png) no-repeat right -96px; 292 | } 293 | 294 | button.submit-button span { 295 | background: transparent url(images/submit-button-bg.png) no-repeat left top; 296 | color: #F9EDD5; 297 | } 298 | 299 | button.submit-button:hover span, button.submit-button-hover span { 300 | color: #FFF 301 | } 302 | 303 | button.submit-button:active span, button.submit.button-active span { 304 | color: #FFF; 305 | } 306 | 307 | 308 | button.call-button { 309 | background: transparent url(images/call-button-bg.png) no-repeat right -96px; 310 | } 311 | 312 | button.call-button span { 313 | background: transparent url(images/call-button-bg.png) no-repeat left top; 314 | color: #F9EDD5; 315 | } 316 | 317 | button.call-button:hover span, button.call-button-hover span { 318 | color: #FFF; 319 | } 320 | 321 | button.call-button:active span, button.call-button-active span { 322 | color: #FFF; 323 | } 324 | 325 | button.sms-button { 326 | background: transparent url(images/sms-button-bg.png) no-repeat right -96px; 327 | } 328 | 329 | button.sms-button span { 330 | background: transparent url(images/sms-button-bg.png) no-repeat left top; 331 | color: #F9EDD5; 332 | } 333 | 334 | button.sms-button:hover span, button.sms-button-hover span { 335 | color: #FFF; 336 | } 337 | 338 | button.sms-button:active span, button.sms-button-active span { 339 | color: #FFF; 340 | } 341 | 342 | 343 | .quick-call-button { 344 | background: url(images/quick-call-button-bg.png) no-repeat center top; 345 | } 346 | 347 | .quick-sms-button { 348 | background: url(images/quick-sms-button-bg.png) no-repeat center top; 349 | } 350 | 351 | 352 | .playback-button { 353 | background: url(images/play-pause-stop-bg.png) no-repeat left top; 354 | } 355 | 356 | .assign-button { 357 | background: url(images/assign-owner-button-bg.png) no-repeat right top; 358 | } 359 | 360 | 361 | .player .load-bar { 362 | background-color: #FFF; 363 | } 364 | 365 | .player .play-bar { 366 | background-color: #C00; 367 | -moz-border-radius: 4px; 368 | -webkit-border-radius: 4px; 369 | } 370 | 371 | 372 | /* Pagination */ 373 | 374 | 375 | 376 | 377 | /* Dialog */ 378 | 379 | .ui-widget-overlay { 380 | background-image: url(images/bg-overlay.png); 381 | } 382 | 383 | 384 | a { 385 | font-style: none; 386 | text-decoration: none; 387 | border: none; 388 | } 389 | a:hover { 390 | text-decoration: none; 391 | border: none; 392 | } 393 | 394 | a:button { 395 | text-decoration: none; 396 | border: none; 397 | } -------------------------------------------------------------------------------- /assets/images/action-icons-mini-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/action-icons-mini-sprite.png -------------------------------------------------------------------------------- /assets/images/action-icons-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/action-icons-sprite.png -------------------------------------------------------------------------------- /assets/images/ajax-loader-circle-dark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/ajax-loader-circle-dark.gif -------------------------------------------------------------------------------- /assets/images/ajax-loader-circle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/ajax-loader-circle.gif -------------------------------------------------------------------------------- /assets/images/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/ajax-loader.gif -------------------------------------------------------------------------------- /assets/images/applet-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/applet-drag-grip.png -------------------------------------------------------------------------------- /assets/images/applet-icons-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/applet-icons-sprite.png -------------------------------------------------------------------------------- /assets/images/assign-owner-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/assign-owner-button-bg.png -------------------------------------------------------------------------------- /assets/images/button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/button-bg.png -------------------------------------------------------------------------------- /assets/images/call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/call-button-bg.png -------------------------------------------------------------------------------- /assets/images/client-first-run-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/client-first-run-arrow.png -------------------------------------------------------------------------------- /assets/images/client-first-run-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/client-first-run-bg.png -------------------------------------------------------------------------------- /assets/images/device-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/device-drag-grip.png -------------------------------------------------------------------------------- /assets/images/devices-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/devices-icon.png -------------------------------------------------------------------------------- /assets/images/dropdown-select-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/dropdown-select-button-bg.png -------------------------------------------------------------------------------- /assets/images/email-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/email-button-bg.png -------------------------------------------------------------------------------- /assets/images/flowline-nav-arrows-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/flowline-nav-arrows-sprite.png -------------------------------------------------------------------------------- /assets/images/flows-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/flows-icon.png -------------------------------------------------------------------------------- /assets/images/form-input-text-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/form-input-text-150.png -------------------------------------------------------------------------------- /assets/images/form-input-text-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/form-input-text-200.png -------------------------------------------------------------------------------- /assets/images/form-input-text-300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/form-input-text-300.png -------------------------------------------------------------------------------- /assets/images/form-input-text-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/form-input-text-50.png -------------------------------------------------------------------------------- /assets/images/form-input-text-600.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/form-input-text-600.png -------------------------------------------------------------------------------- /assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/icon.png -------------------------------------------------------------------------------- /assets/images/info-banner-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/info-banner-icon.png -------------------------------------------------------------------------------- /assets/images/main-context-menu-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/main-context-menu-bg.png -------------------------------------------------------------------------------- /assets/images/message-status-icon-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/message-status-icon-bg.png -------------------------------------------------------------------------------- /assets/images/messages-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/messages-icon.png -------------------------------------------------------------------------------- /assets/images/mic_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/mic_big.png -------------------------------------------------------------------------------- /assets/images/normal-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/normal-button-bg.png -------------------------------------------------------------------------------- /assets/images/numbers-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/numbers-icon.png -------------------------------------------------------------------------------- /assets/images/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/overlay.png -------------------------------------------------------------------------------- /assets/images/play-pause-stop-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/play-pause-stop-bg.png -------------------------------------------------------------------------------- /assets/images/quick-call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/quick-call-button-bg.png -------------------------------------------------------------------------------- /assets/images/quick-call-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/quick-call-popup-button-bg.png -------------------------------------------------------------------------------- /assets/images/quick-sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/quick-sms-button-bg.png -------------------------------------------------------------------------------- /assets/images/quick-sms-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/quick-sms-popup-button-bg.png -------------------------------------------------------------------------------- /assets/images/remove-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/remove-user.png -------------------------------------------------------------------------------- /assets/images/sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/sms-button-bg.png -------------------------------------------------------------------------------- /assets/images/standard-icons-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/standard-icons-sprite.png -------------------------------------------------------------------------------- /assets/images/submit-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/submit-button-bg.png -------------------------------------------------------------------------------- /assets/images/timepicker-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/timepicker-add.png -------------------------------------------------------------------------------- /assets/images/timepicker-remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/timepicker-remove.png -------------------------------------------------------------------------------- /assets/images/toggle-arrow-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/toggle-arrow-16.png -------------------------------------------------------------------------------- /assets/images/user-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/user-drag-grip.png -------------------------------------------------------------------------------- /assets/images/user-group-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/user-group-icon.png -------------------------------------------------------------------------------- /assets/images/user-group-picker-group-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/user-group-picker-group-icon.png -------------------------------------------------------------------------------- /assets/images/user-group-picker-person-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/user-group-picker-person-icon.png -------------------------------------------------------------------------------- /assets/images/user-group-utilities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/user-group-utilities.png -------------------------------------------------------------------------------- /assets/images/user-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/user-icon.png -------------------------------------------------------------------------------- /assets/images/user-list-status-icon-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/user-list-status-icon-sprite.png -------------------------------------------------------------------------------- /assets/images/voicemail-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/images/voicemail-icon.png -------------------------------------------------------------------------------- /assets/mandala/images/assign-owner-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/assign-owner-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/call-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/dropdown-select-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/dropdown-select-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/main-context-menu-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/main-context-menu-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/normal-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/normal-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/play-message-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/play-message-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/play-pause-stop-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/play-pause-stop-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/quick-call-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/quick-call-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/quick-call-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/quick-call-popup-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/quick-sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/quick-sms-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/quick-sms-popup-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/quick-sms-popup-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/quick-sms-send-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/quick-sms-send-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/sms-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/sms-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/submit-button-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/submit-button-bg.png -------------------------------------------------------------------------------- /assets/mandala/images/user-drag-grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mandala/images/user-drag-grip.png -------------------------------------------------------------------------------- /assets/mandala/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: Zen 3 | */ 4 | 5 | /* Links */ 6 | 7 | .mandala-theme a:link { 8 | color: #679515; 9 | } 10 | 11 | .mandala-theme a:visited { 12 | color: #7D9B39; 13 | } 14 | 15 | .mandala-theme a:hover { 16 | color: #616542; 17 | } 18 | 19 | .mandala-theme a:active { 20 | color: #679515; 21 | } 22 | 23 | 24 | #context-menu { 25 | padding: 5px; 26 | background: #616542 url(images/main-context-menu-bg.png) repeat-x left top; 27 | border-bottom: 1px solid #FFF; 28 | overflow: auto; 29 | -moz-border-radius-topleft: 4px; 30 | -moz-border-radius-topright: 4px; 31 | -webkit-border-radius-topleft: 4px; 32 | -webkit-border-radius-topright: 4px; 33 | } 34 | 35 | /* VBX Main Navigation */ 36 | 37 | #main-nav .nav-title { 38 | padding: 4px 10px; 39 | font-size: 11px; 40 | font-weight: bold; 41 | color: #DAE5C3; 42 | text-transform: uppercase; 43 | background-color: #679515; 44 | border-bottom: 2px solid #616542; 45 | } 46 | 47 | #main-nav .nav-item a { 48 | display: block; 49 | padding: 6px 5px 6px 10px; 50 | font-size: 14px; 51 | color: #616542; 52 | text-decoration: none; 53 | background-color: #DAE5C3; 54 | border-top: 1px solid #FFF; 55 | overflow: auto; 56 | } 57 | 58 | #main-nav .nav-item a:hover { 59 | color: #FFF; 60 | background-color: #E3AC2B; 61 | } 62 | 63 | #main-nav .selected a, 64 | #main-nav .selected a:hover { 65 | width: 166px; 66 | font-size: 14px; 67 | font-weight: bold; 68 | color: #F7ECB7; 69 | background-color: #333; 70 | border-bottom: 1px solid #000; 71 | } 72 | 73 | 74 | 75 | /* Content Menu */ 76 | 77 | .content-menu .menu-item a.link-button { 78 | background: url(images/button-bg.png) no-repeat right -96px; 79 | } 80 | 81 | .content-menu .menu-item a.dropdown-select-button { 82 | background: url(images/dropdown-select-button-bg.png) no-repeat right -96px; 83 | } 84 | 85 | .content-menu .menu-item a.link-button span { 86 | color: #FFF; 87 | background: url(images/button-bg.png) no-repeat left top; 88 | } 89 | 90 | .content-menu .menu-item a.dropdown-select-button span { 91 | color: #FFF; 92 | background: url(images/dropdown-select-button-bg.png) no-repeat left top; 93 | } 94 | 95 | 96 | 97 | /* Content Items Grid */ 98 | 99 | .items-grid { 100 | background-color: #DAE5C3; 101 | border: 3px solid #DAE5C3; 102 | } 103 | 104 | .items-grid .log-head-row th { 105 | background-color: #DDD; 106 | border-bottom: 1px solid #CCC; 107 | } 108 | 109 | .items-grid .log-row td { 110 | background-color: #EEE; 111 | border-bottom: 1px solid #CCC; 112 | } 113 | 114 | .items-grid .message-row td { 115 | color: #777; 116 | background-color: #F7F9F2; 117 | border-bottom: 1px solid #DAE5C3; 118 | } 119 | 120 | .items-grid .unread td { 121 | color: #222; 122 | background-color: #FFF; 123 | } 124 | 125 | .items-grid .unread .phone-number { 126 | color: #679515; 127 | } 128 | 129 | .items-grid .message-row .phone-number { 130 | color: #7D9B39; 131 | } 132 | 133 | .items-grid .hover td { 134 | background-color: #FCF8E4; 135 | } 136 | 137 | .items-grid .mousedown td { 138 | background-color: #F7ECB7; 139 | } 140 | 141 | .items-grid .clicked td { 142 | background-color: #F7ECB7; 143 | } 144 | 145 | .items-grid .checked td { 146 | background-color: #F7ECB7; 147 | } 148 | 149 | 150 | 151 | .items-grid .quick-call-popup .call { 152 | display: block; 153 | height: 28px; 154 | line-height: 28px; 155 | width: 42px; 156 | padding-left: 24px; 157 | font-size: 16px; 158 | font-weight: bold; 159 | color: #FFF; 160 | text-decoration: none; 161 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 162 | } 163 | 164 | .items-grid .quick-sms-popup .send-button { 165 | height: 28px; 166 | width: 80px; 167 | margin-left: 10px; 168 | padding-left: 24px; 169 | font-size: 16px; 170 | font-weight: bold; 171 | color: #FFF; 172 | background: url(images/quick-sms-send-button-bg.png) no-repeat center center; 173 | } 174 | 175 | 176 | 177 | /* Message Details*/ 178 | 179 | .message-details-header .quick-call-popup .call { 180 | display: block; 181 | height: 28px; 182 | line-height: 28px; 183 | width: 42px; 184 | padding-left: 20px; 185 | font-size: 16px; 186 | font-weight: bold; 187 | color: #FFF; 188 | text-decoration: none; 189 | background: url(images/quick-call-popup-button-bg.png) no-repeat center center; 190 | } 191 | 192 | 193 | 194 | /* Admin */ 195 | 196 | #user-container .user { 197 | display: inline-block; 198 | width: 221px; 199 | margin: 0 10px 10px 0; 200 | padding: 20px 10px 10px 10px; 201 | background: #FFF url(images/user-drag-grip.png) no-repeat center 2px; 202 | cursor: move; 203 | overflow: hidden; 204 | border: 1px solid #777; 205 | -moz-border-radius: 4px; 206 | -webkit-border-radius: 4px; 207 | } 208 | 209 | 210 | /* Buttons */ 211 | 212 | button.normal-button { 213 | background: transparent url(images/normal-button-bg.png) no-repeat right -96px; 214 | } 215 | 216 | button.normal-button span { 217 | background: transparent url(images/normal-button-bg.png) no-repeat left top; 218 | color: #F9EDD5; 219 | } 220 | 221 | button.normal-button:hover span, button.normal-button-hover span { 222 | color: #FFF 223 | } 224 | 225 | button.normal-button:active span, button.normal-button-active span { 226 | color: #FFF; 227 | } 228 | 229 | 230 | button.submit-button { 231 | background: transparent url(images/submit-button-bg.png) no-repeat right -96px; 232 | } 233 | 234 | button.submit-button span { 235 | background: transparent url(images/submit-button-bg.png) no-repeat left top; 236 | color: #F9EDD5; 237 | } 238 | 239 | button.submit-button:hover span, button.submit-button-hover span { 240 | color: #FFF 241 | } 242 | 243 | button.submit-button:active span, button.submit.button-active span { 244 | color: #FFF; 245 | } 246 | 247 | 248 | button.call-button { 249 | background: transparent url(images/call-button-bg.png) no-repeat right -96px; 250 | } 251 | 252 | button.call-button span { 253 | background: transparent url(images/call-button-bg.png) no-repeat left top; 254 | color: #F9EDD5; 255 | } 256 | 257 | button.call-button:hover span, button.call-button-hover span { 258 | color: #FFF; 259 | } 260 | 261 | button.call-button:active span, button.call-button-active span { 262 | color: #FFF; 263 | } 264 | 265 | button.sms-button { 266 | background: transparent url(images/sms-button-bg.png) no-repeat right -96px; 267 | } 268 | 269 | button.sms-button span { 270 | background: transparent url(images/sms-button-bg.png) no-repeat left top; 271 | color: #F9EDD5; 272 | } 273 | 274 | button.sms-button:hover span, button.sms-button-hover span { 275 | color: #FFF; 276 | } 277 | 278 | button.sms-button:active span, button.sms-button-active span { 279 | color: #FFF; 280 | } 281 | 282 | 283 | .quick-call-button { 284 | background: url(images/quick-call-button-bg.png) no-repeat center top; 285 | } 286 | 287 | .quick-sms-button { 288 | background: url(images/quick-sms-button-bg.png) no-repeat center top; 289 | } 290 | 291 | 292 | .playback-button { 293 | background: url(images/play-message-button-bg.png) no-repeat left top; 294 | } 295 | 296 | .assign-button { 297 | background: url(images/assign-owner-button-bg.png) no-repeat right top; 298 | } 299 | 300 | a { 301 | font-style: none; 302 | text-decoration: none; 303 | border: none; 304 | } 305 | a:hover { 306 | text-decoration: none; 307 | border: none; 308 | } 309 | 310 | a:button { 311 | text-decoration: none; 312 | border: none; 313 | } 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /assets/mediaelement-flash-audio.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mediaelement-flash-audio.swf -------------------------------------------------------------------------------- /assets/mediaelementplayer.min.css: -------------------------------------------------------------------------------- 1 | .mejs__offscreen{border:0;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal}.mejs__container{background:#000;box-sizing:border-box;font-family:Helvetica,Arial,serif;position:relative;text-align:left;text-indent:0;vertical-align:top}.mejs__container .mejs__video{min-height:140px}.mejs__container *{box-sizing:border-box}.mejs__container video::-webkit-media-controls-start-playback-button{-webkit-appearance:none;display:none!important}.mejs__fill-container,.mejs__fill-container .mejs__container{height:100%;width:100%}.mejs__fill-container{background:transparent;margin:0 auto;overflow:hidden;position:relative}.mejs__container:focus{outline:none}.mejs__iframe-overlay{height:100%;position:absolute;width:100%}.mejs__embed,.mejs__embed body{background:#000;height:100%;margin:0;overflow:hidden;padding:0;width:100%}.mejs__fullscreen{overflow:hidden!important}.mejs__container-fullscreen{bottom:0;left:0;overflow:hidden;position:fixed;right:0;top:0;z-index:4}.mejs__container-fullscreen .mejs__mediaelement,.mejs__container-fullscreen video{height:100%!important;width:100%!important}.mejs__background,.mejs__mediaelement{left:0;position:absolute;top:0}.mejs__mediaelement{height:100%;width:100%;z-index:0}.mejs__poster{background-position:50% 50%;background-repeat:no-repeat;background-size:contain;left:0;position:absolute;top:0;z-index:1}:root .mejs__poster-img{display:none}.mejs__poster-img{border:0;padding:0}.mejs__overlay{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:absolute;top:0}.mejs__layer{z-index:1}.mejs__overlay-play{cursor:pointer}.mejs__overlay-button{background:url(mejs-controls.svg) no-repeat;background-position:0 -39px;height:80px;width:80px}.mejs__overlay:hover>.mejs__overlay-button{background-position:-80px -39px}.mejs__overlay-loading{height:80px;width:80px}.mejs__overlay-loading-bg-img{-webkit-animation:a 1s linear infinite;animation:a 1s linear infinite;background:transparent url(mejs-controls.svg) -160px -40px no-repeat;display:block;height:80px;width:80px;z-index:1}@-webkit-keyframes a{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes a{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.mejs__controls{bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:40px;left:0;list-style-type:none;margin:0;padding:0 10px;position:absolute;width:100%;z-index:1}.mejs__controls:not([style*="display: none"]){background:rgba(255,0,0,.7);background:-webkit-linear-gradient(transparent,rgba(0,0,0,.35));background:linear-gradient(transparent,rgba(0,0,0,.35))}.mejs__button,.mejs__time,.mejs__time-rail{font-size:10px;height:40px;line-height:10px;margin:0;width:32px}.mejs__button>button{background:transparent url(mejs-controls.svg);border:0;cursor:pointer;display:block;font-size:0;height:20px;line-height:0;margin:10px 6px;overflow:hidden;padding:0;position:absolute;text-decoration:none;width:20px}.mejs__button>button:focus{outline:1px dotted #999}.mejs__container-keyboard-inactive [role=slider],.mejs__container-keyboard-inactive [role=slider]:focus,.mejs__container-keyboard-inactive a,.mejs__container-keyboard-inactive a:focus,.mejs__container-keyboard-inactive button,.mejs__container-keyboard-inactive button:focus{outline:0}.mejs__time{box-sizing:content-box;color:#fff;font-size:11px;font-weight:700;height:24px;overflow:hidden;padding:16px 6px 0;text-align:center;width:auto}.mejs__play>button{background-position:0 0}.mejs__pause>button{background-position:-20px 0}.mejs__replay>button{background-position:-160px 0}.mejs__time-rail{direction:ltr;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;height:40px;margin:0 10px;padding-top:10px;position:relative}.mejs__time-buffering,.mejs__time-current,.mejs__time-float,.mejs__time-float-corner,.mejs__time-float-current,.mejs__time-hovered,.mejs__time-loaded,.mejs__time-marker,.mejs__time-total{border-radius:2px;cursor:pointer;display:block;height:10px;position:absolute}.mejs__time-total{background:hsla(0,0%,100%,.3);margin:5px 0 0;width:100%}.mejs__time-buffering{-webkit-animation:b 2s linear infinite;animation:b 2s linear infinite;background:-webkit-linear-gradient(135deg,hsla(0,0%,100%,.4) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.4) 0,hsla(0,0%,100%,.4) 75%,transparent 0,transparent);background:linear-gradient(-45deg,hsla(0,0%,100%,.4) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.4) 0,hsla(0,0%,100%,.4) 75%,transparent 0,transparent);background-size:15px 15px;width:100%}@-webkit-keyframes b{0%{background-position:0 0}to{background-position:30px 0}}@keyframes b{0%{background-position:0 0}to{background-position:30px 0}}.mejs__time-loaded{background:hsla(0,0%,100%,.3)}.mejs__time-current,.mejs__time-handle-content{background:hsla(0,0%,100%,.9)}.mejs__time-hovered{background:hsla(0,0%,100%,.5);z-index:2}.mejs__time-hovered.negative{background:rgba(0,0,0,.2)}.mejs__time-buffering,.mejs__time-current,.mejs__time-hovered,.mejs__time-loaded{left:0;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-transition:all .15s ease-in;transition:all .15s ease-in;width:100%}.mejs__time-buffering{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1)}.mejs__time-hovered{-webkit-transition:height .1s cubic-bezier(.44,0,1,1);transition:height .1s cubic-bezier(.44,0,1,1)}.mejs__time-hovered.no-hover{-webkit-transform:scaleX(0)!important;-ms-transform:scaleX(0)!important;transform:scaleX(0)!important}.mejs__time-handle,.mejs__time-handle-content{border:4px solid transparent;cursor:pointer;left:0;position:absolute;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);z-index:3}.mejs__time-handle-content{border:4px solid hsla(0,0%,100%,.9);border-radius:50%;height:10px;left:-7px;top:-4px;-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0);width:10px}.mejs__time-rail .mejs__time-handle-content:active,.mejs__time-rail .mejs__time-handle-content:focus,.mejs__time-rail:hover .mejs__time-handle-content{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}.mejs__time-float{background:#eee;border:1px solid #333;bottom:100%;color:#111;display:none;height:17px;margin-bottom:9px;position:absolute;text-align:center;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:36px}.mejs__time-float-current{display:block;left:0;margin:2px;text-align:center;width:30px}.mejs__time-float-corner{border:5px solid #eee;border-color:#eee transparent transparent;border-radius:0;display:block;height:0;left:50%;line-height:0;position:absolute;top:100%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:0}.mejs__long-video .mejs__time-float{margin-left:-23px;width:64px}.mejs__long-video .mejs__time-float-current{width:60px}.mejs__broadcast{color:#fff;height:10px;position:absolute;top:15px;width:100%}.mejs__fullscreen-button>button{background-position:-80px 0}.mejs__unfullscreen>button{background-position:-100px 0}.mejs__mute>button{background-position:-60px 0}.mejs__unmute>button{background-position:-40px 0}.mejs__volume-button{position:relative}.mejs__volume-button>.mejs__volume-slider{background:rgba(50,50,50,.7);border-radius:0;bottom:100%;display:none;height:115px;left:50%;margin:0;position:absolute;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:25px;z-index:1}.mejs__volume-button:hover{border-radius:0 0 4px 4px}.mejs__volume-total{background:hsla(0,0%,100%,.5);height:100px;left:50%;margin:0;position:absolute;top:8px;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:2px}.mejs__volume-current{left:0;margin:0;width:100%}.mejs__volume-current,.mejs__volume-handle{background:hsla(0,0%,100%,.9);position:absolute}.mejs__volume-handle{border-radius:1px;cursor:ns-resize;height:6px;left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:16px}.mejs__horizontal-volume-slider{display:block;height:36px;position:relative;vertical-align:middle;width:56px}.mejs__horizontal-volume-total{background:rgba(50,50,50,.8);height:8px;top:16px;width:50px}.mejs__horizontal-volume-current,.mejs__horizontal-volume-total{border-radius:2px;font-size:1px;left:0;margin:0;padding:0;position:absolute}.mejs__horizontal-volume-current{background:hsla(0,0%,100%,.8);height:100%;top:0;width:100%}.mejs__horizontal-volume-handle{display:none}.mejs__captions-button,.mejs__chapters-button{position:relative}.mejs__captions-button>button{background-position:-140px 0}.mejs__chapters-button>button{background-position:-180px 0}.mejs__captions-button>.mejs__captions-selector,.mejs__chapters-button>.mejs__chapters-selector{background:rgba(50,50,50,.7);border:1px solid transparent;border-radius:0;bottom:100%;margin-right:-43px;overflow:hidden;padding:0;position:absolute;right:50%;visibility:visible;width:86px}.mejs__chapters-button>.mejs__chapters-selector{margin-right:-55px;width:110px}.mejs__captions-selector-list,.mejs__chapters-selector-list{list-style-type:none!important;margin:0;overflow:hidden;padding:0}.mejs__captions-selector-list-item,.mejs__chapters-selector-list-item{color:#fff;cursor:pointer;display:block;list-style-type:none!important;margin:0 0 6px;overflow:hidden;padding:0 10px}.mejs__captions-selector-list-item:hover,.mejs__chapters-selector-list-item:hover{background-color:#c8c8c8!important;background-color:hsla(0,0%,100%,.4)!important}.mejs__captions-selector-input,.mejs__chapters-selector-input{clear:both;float:left;left:-1000px;margin:3px 3px 0 5px;position:absolute}.mejs__captions-selector-label,.mejs__chapters-selector-label{cursor:pointer;float:left;font-size:10px;line-height:15px;padding:4px 0 0}.mejs__captions-selected,.mejs__chapters-selected{color:#21f8f8}.mejs__captions-translations{font-size:10px;margin:0 0 5px}.mejs__captions-layer{bottom:0;color:#fff;font-size:16px;left:0;line-height:20px;position:absolute;text-align:center}.mejs__captions-layer a{color:#fff;text-decoration:underline}.mejs__captions-layer[lang=ar]{font-size:20px;font-weight:400}.mejs__captions-position{bottom:15px;left:0;position:absolute;width:100%}.mejs__captions-position-hover{bottom:35px}.mejs__captions-text,.mejs__captions-text *{background:hsla(0,0%,8%,.5);box-shadow:5px 0 0 hsla(0,0%,8%,.5),-5px 0 0 hsla(0,0%,8%,.5);padding:0;white-space:pre-wrap}.mejs__container.mejs__hide-cues video::-webkit-media-text-track-container{display:none}.mejs__cannotplay,.mejs__cannotplay a{color:#fff;font-size:.8em}.mejs__cannotplay a,.mejs__cannotplay p{display:inline-block;padding:0 15px;width:100%} -------------------------------------------------------------------------------- /assets/mejs-controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/assets/mejs-controls.png -------------------------------------------------------------------------------- /assets/mejs-controls.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /googlevoice.php: -------------------------------------------------------------------------------- 1 | _login = $login; 12 | $this->_pass = urlencode($pass); 13 | } 14 | 15 | public function messages($googleitem) 16 | { 17 | $Email = $this->_login; 18 | $Passwd = $this->_pass; 19 | $this->msg_messages = shell_exec("./gvmessages.py $Email $Passwd $googleitem"); 20 | return json_decode($this->msg_messages); 21 | } 22 | 23 | public function getvoicemail() 24 | { 25 | $Email = $this->_login; 26 | $Passwd = $this->_pass; 27 | $this->msg_messages = shell_exec("./gvvoicemail-mp3.py $Email $Passwd"); 28 | return json_decode($this->msg_messages); 29 | } 30 | public function getrecorded() 31 | { 32 | $Email = $this->_login; 33 | $Passwd = $this->_pass; 34 | $this->msg_messages = shell_exec("./gvrecorded-mp3.py $Email $Passwd"); 35 | return json_decode($this->msg_messages); 36 | } 37 | public function getmessages($googleitem, $phonesearch) 38 | { 39 | $Email = $this->_login; 40 | $Passwd = $this->_pass; 41 | $this->msg_messages = shell_exec("./gvgetmessages.py $Email $Passwd $googleitem $phonesearch"); 42 | return json_decode($this->msg_messages); 43 | } 44 | 45 | public function getdetails($googleitem, $msgID) 46 | { 47 | $Email = $this->_login; 48 | $Passwd = $this->_pass; 49 | $this->msg_messages = shell_exec("./gvdetails.py $Email $Passwd $googleitem $msgID"); 50 | return json_decode($this->msg_messages); 51 | } 52 | 53 | public function history($googleitem, $msgID) 54 | { 55 | $Email = $this->_login; 56 | $Passwd = $this->_pass; 57 | $this->msg_messages = shell_exec("./gvhistory.py $Email $Passwd $googleitem $msgID"); 58 | return json_decode($this->msg_messages); 59 | } 60 | 61 | public function checksetting($googleitem) 62 | { 63 | $Email = $this->_login; 64 | $Passwd = $this->_pass; 65 | $this->msg_messages = shell_exec("./gvsettingcheck.py $Email $Passwd $googleitem"); 66 | return json_decode($this->msg_messages); 67 | } 68 | 69 | public function actions($gvfolder, $googleitem, $msgID) 70 | { 71 | $Email = $this->_login; 72 | $Passwd = $this->_pass; 73 | $dataID = escapeshellarg(json_encode($msgID)); 74 | $this->msg_messages = shell_exec("./gvactions.py $Email $Passwd $gvfolder $googleitem $dataID"); 75 | return $this->msg_messages; 76 | } 77 | 78 | public function addNote($gvfolder, $msgID, $note) 79 | { 80 | $Email = $this->_login; 81 | $Passwd = $this->_pass; 82 | $text = escapeshellarg(json_encode($note)); 83 | $this->msg_messages = shell_exec("./gvaddNote.py $Email $Passwd $gvfolder $msgID $text"); 84 | return $this->msg_messages; 85 | } 86 | 87 | public function call($to_phonenumber, $from_phonenumber, $type_phone) 88 | { 89 | $Email = $this->_login; 90 | $Passwd = $this->_pass; 91 | $phonenumber = preg_replace('#[^0-9]#','',strip_tags($to_phonenumber)); 92 | $this->status = shell_exec("./gvcall.py $Email $Passwd $phonenumber $from_phonenumber $type_phone"); 93 | return $this->status; 94 | } 95 | 96 | public function cancelcall($to_phonenumber, $from_phonenumber, $type_phone) 97 | { 98 | $Email = $this->_login; 99 | $Passwd = $this->_pass; 100 | $phonenumber = preg_replace('#[^0-9]#','',strip_tags($to_phonenumber)); 101 | $this->status = shell_exec("./gvcallcancel.py $Email $Passwd $phonenumber $from_phonenumber $type_phone"); 102 | return $this->status; 103 | } 104 | 105 | public function sms($to_phonenumber, $smstxt) 106 | { 107 | $Email = $this->_login; 108 | $Passwd = $this->_pass; 109 | $text = escapeshellarg(json_encode($smstxt)); 110 | $this->status = shell_exec("./gvsendsms.py $Email $Passwd $to_phonenumber $text"); 111 | return $this->status; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /gvactions.php: -------------------------------------------------------------------------------- 1 | sms($number, $message); 16 | break; 17 | case 'callNumber' : 18 | $results = $google->call($_POST['numberToCall'], $forwardingPhone, $phoneType); 19 | break; 20 | case 'cancelCall' : 21 | $results = $google->cancelcall($_POST['numberToCall'], $forwardingPhone, $phoneType); 22 | break; 23 | case 'addNote' : 24 | $results = $google->addNote($_SESSION['pidcommand'],$_POST['messageId'],$_POST['messagenote']); 25 | break; 26 | case 'removeNote' : 27 | $results = $google->actions($_SESSION['pidcommand'],"unNoted",$_POST['messageId']); 28 | break; 29 | case 'star' : 30 | $results = $google->actions($_SESSION['pidcommand'],"Starred", $_POST['messageId']); 31 | break; 32 | case 'unStar' : 33 | $results = $google->actions($_SESSION['pidcommand'],"unStarred", $_POST['messageId']); 34 | break; 35 | case 'markRead' : 36 | $results = $google->actions($_SESSION['pidcommand'],"markRead", $_POST['messageId']); 37 | break; 38 | case 'unread' : 39 | $results = $google->actions($_SESSION['pidcommand'],"markUnread", $_POST['messageId']); 40 | break; 41 | case 'archive' : 42 | $results = $google->actions($_SESSION['pidcommand'],"Archived", $_POST['messageId']); 43 | break; 44 | case 'unArchive' : 45 | $results = $google->actions($_SESSION['pidcommand'],"unArchived", $_POST['messageId']); 46 | break; 47 | case 'block' : 48 | $results = $google->actions($_SESSION['pidcommand'],"Blocked", $_POST['messageId']); 49 | break; 50 | case 'unblock' : 51 | $results = $google->actions($_SESSION['pidcommand'],"unBlocked", $_POST['messageId']); 52 | break; 53 | case 'delete' : 54 | $results = $google->actions($_SESSION['pidcommand'],"Deleted", $_POST['messageId']); 55 | break; 56 | } 57 | } 58 | if (!empty($results)) 59 | echo $results; 60 | ?> 61 | -------------------------------------------------------------------------------- /gvactions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | import json 5 | 6 | def doactions(count, gvaction, msgID, getID) : 7 | if ((gvaction == "Deleted") and (msgID in getID)) : 8 | message.delete() 9 | count = count + 1 10 | elif ((gvaction == "unDeleted") and (msgID in getID)) : 11 | message.delete(0) 12 | count = count + 1 13 | elif ((gvaction == "unArchived") and (msgID in getID)) : 14 | message.archive(0) 15 | count = count + 1 16 | elif ((gvaction == "Archived") and (msgID in getID)) : 17 | message.archive() 18 | count = count + 1 19 | elif ((gvaction == "markUnread") and (msgID in getID)) : 20 | message.mark(0) 21 | count = count + 1 22 | elif ((gvaction == "markRead") and (msgID in getID)) : 23 | message.mark() 24 | count = count + 1 25 | elif ((gvaction == "unStarred") and (msgID in getID)) : 26 | message.star(0) 27 | count = count + 1 28 | elif ((gvaction == "Starred") and (msgID in getID)) : 29 | message.star() 30 | count = count + 1 31 | elif ((gvaction == "unBlocked") and (msgID in getID)) : 32 | message.block(0) 33 | count = count + 1 34 | elif ((gvaction == "Blocked") and (msgID in getID)) : 35 | message.block() 36 | count = count + 1 37 | elif ((gvaction == "unNoted") and (msgID in getID)) : 38 | message.deleteNote() 39 | count = count + 1 40 | return count 41 | 42 | voice = Voice() 43 | try: 44 | email = argv[1] 45 | except: 46 | print ('Error! Please provide Email Account. ') 47 | exit(0) 48 | try: 49 | password = argv[2] 50 | except: 51 | print ('Error! Please provide Passsword. ') 52 | exit(0) 53 | try: 54 | voice.login(email,password) 55 | except: 56 | print ('Error! Login failed. ') 57 | exit(0) 58 | 59 | try: 60 | msgfolder = argv[3] 61 | except: 62 | print ('Error! Please provide a Message Folder an ACTION and Message ID. ') 63 | voice.logout() 64 | exit(0) 65 | 66 | try: 67 | ACTION = argv[4] 68 | except: 69 | print ('Error! Please provide a ACTION and Message ID. ') 70 | voice.logout() 71 | exit(0) 72 | try: 73 | ID = json.loads(argv[5]) 74 | except: 75 | print ('Error! Please provide a Message ID. ') 76 | voice.logout() 77 | exit(0) 78 | 79 | counter = 0 80 | try: 81 | if msgfolder == "Inbox" : 82 | msglen = len(voice.inbox().messages) 83 | for message in voice.inbox().messages: 84 | counter = doactions(counter, ACTION, message.id , ID) 85 | if (msglen == counter) : 86 | break 87 | elif msgfolder == "Voicemail" : 88 | msglen = len(voice.voicemail().messages) 89 | for message in voice.voicemail().messages: 90 | counter = doactions(counter, ACTION, message.id , ID) 91 | if (msglen == counter) : 92 | break 93 | elif msgfolder == "Recorded" : 94 | msglen = len(voice.recorded().messages) 95 | for message in voice.recorded().messages: 96 | counter = doactions(counter, ACTION, message.id , ID) 97 | if (msglen == counter) : 98 | break 99 | elif msgfolder == "Messages" : 100 | msglen = len(voice.sms().messages) 101 | for message in voice.sms().messages: 102 | counter = doactions(counter, ACTION, message.id , ID) 103 | if (msglen == counter) : 104 | break 105 | elif msgfolder == "All" : 106 | voice.all() 107 | folder = voice.all.folder 108 | msglen = len(folder.messages) 109 | for message in folder.messages: 110 | counter = doactions(counter, ACTION, message.id , ID) 111 | if (msglen == counter) : 112 | break 113 | elif msgfolder == "Placed" : 114 | msglen = len(voice.placed().messages) 115 | for message in voice.placed().messages: 116 | counter = doactions(counter, ACTION, message.id , ID) 117 | if (msglen == counter) : 118 | break 119 | elif msgfolder == "Received" : 120 | msglen = len(voice.received().messages) 121 | for message in voice.received().messages: 122 | counter = doactions(counter, ACTION, message.id , ID) 123 | if (msglen == counter) : 124 | break 125 | elif msgfolder == "Spam" : 126 | voice.spam() 127 | folder = voice.spam.folder 128 | msglen = len(folder.messages) 129 | for message in folder.messages: 130 | counter = doactions(counter, ACTION, message.id , ID) 131 | if (msglen == counter) : 132 | break 133 | elif msgfolder == "Trash" : 134 | voice.trash() 135 | folder = voice.trash.folder 136 | msglen = len(folder.messages) 137 | for message in folder.messages: 138 | counter = doactions(counter, ACTION, message.id , ID) 139 | if (msglen == counter) : 140 | break 141 | elif msgfolder == "Missed" : 142 | msglen = len(voice.missed().messages) 143 | for message in voice.missed().messages: 144 | counter = doactions(counter, ACTION, message.id , ID) 145 | if (msglen == counter) : 146 | break 147 | except: 148 | print ("Error! With" + msgfolder +", " + ACTION + " and " + ID + "Message ID's.") 149 | 150 | print ACTION + " " + str(counter) + " Messages." 151 | voice.logout() 152 | -------------------------------------------------------------------------------- /gvaddnote.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | import json 5 | 6 | voice = Voice() 7 | try: 8 | email = argv[1] 9 | except: 10 | print ('Error! Please provide Email Account. ') 11 | exit(0) 12 | try: 13 | password = argv[2] 14 | except: 15 | print ('Error! Please provide Passsword. ') 16 | exit(0) 17 | try: 18 | voice.login(email,password) 19 | except: 20 | print ('Error! Login failed. ') 21 | exit(0) 22 | 23 | try: 24 | msgfolder = argv[3] 25 | except: 26 | print ('Error! Please provide a Message Folder an Message ID and NOTES. ') 27 | voice.logout() 28 | exit(0) 29 | 30 | try: 31 | ID = argv[4] 32 | except: 33 | print ('Error! Please provide a Message ID and NOTES. ') 34 | voice.logout() 35 | exit(0) 36 | try: 37 | NOTES = json.loads(argv[5]) 38 | except: 39 | print ('Error! Please provide NOTES. ') 40 | voice.logout() 41 | exit(0) 42 | 43 | try: 44 | if msgfolder == "Voicemail" : 45 | for message in voice.voicemail().messages: 46 | if (message.id == ID) : 47 | message.addNote(NOTES) 48 | break 49 | elif msgfolder == "Recorded" : 50 | for message in voice.recorded().messages: 51 | if (message.id == ID) : 52 | message.addNote(NOTES) 53 | break 54 | except: 55 | print ("Error! With" + msgfolder + ", Message ID:" + ID + " and Notes:" + NOTES ) 56 | 57 | print "Notes Added!" 58 | voice.logout() 59 | -------------------------------------------------------------------------------- /gvcall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | 5 | voice = Voice() 6 | try: 7 | email = argv[1] 8 | except: 9 | print ('Error! Please provide Email Account.') 10 | exit(0) 11 | 12 | try: 13 | password = argv[2] 14 | except: 15 | print ('Error! Please provide Passsword.') 16 | exit(0) 17 | 18 | try: 19 | voice.login(email,password) 20 | except: 21 | print ('Error! Login failed.') 22 | exit(0) 23 | 24 | try: 25 | outgoingNumber = argv[3] 26 | except: 27 | print ('Error! Please provide a Number to call ') 28 | voice.logout() 29 | exit(0) 30 | 31 | try: 32 | forwardingNumber = argv[4] 33 | except: 34 | forwardingNumber = None 35 | 36 | try: 37 | numberType = argv[5] 38 | except: 39 | numberType = None 40 | 41 | try: 42 | voice.call(outgoingNumber, forwardingNumber, numberType ) 43 | print ('Calling now...') 44 | except: 45 | print ('Error! Calling failed') 46 | 47 | voice.logout() 48 | -------------------------------------------------------------------------------- /gvcallcancel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | 5 | voice = Voice() 6 | try: 7 | email = argv[1] 8 | except: 9 | print ('Error! Please provide Email Account.') 10 | exit(0) 11 | 12 | try: 13 | password = argv[2] 14 | except: 15 | print ('Error! Please provide Passsword.') 16 | exit(0) 17 | 18 | try: 19 | voice.login(email,password) 20 | except: 21 | print ('Error! Login failed.') 22 | exit(0) 23 | 24 | try: 25 | outgoingNumber = argv[3] 26 | except: 27 | print ('Error! Please provide a Number to cancel ') 28 | voice.logout() 29 | exit(0) 30 | 31 | try: 32 | forwardingNumber = argv[4] 33 | except: 34 | forwardingNumber = None 35 | 36 | try: 37 | numberType = argv[5] 38 | except: 39 | numberType = None 40 | 41 | try: 42 | voice.cancel(outgoingNumber, forwardingNumber, numberType ) 43 | print ('Call canceled!') 44 | except: 45 | print ('Error! Call not canceled') 46 | 47 | voice.logout() 48 | -------------------------------------------------------------------------------- /gvconfig.php: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /gvdetails.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 26 | 28 | 40 | checksetting("SETTING"); 43 | $msgdetails = $google->getdetails($_SESSION['pidcommand'], $getID); 44 | $getTexts = $google->history($_SESSION['pidcommand'], $getID); 45 | $datetime = split(" ",$msgdetails->displayStartDateTime); 46 | //$receivedtime = date("F j, Y, g:i a", strtotime($datetime[0]." ".$msgdetails->displayStartTime) ); 47 | $receivedtime = date("F j, Y", strtotime($datetime[0]) ); 48 | 49 | function MakeUrls($str) 50 | { 51 | $out = str_replace("\n" , '
    ', $str); 52 | $find=array('`((?:https?|ftp)://\S+[[:alnum:]]/?)`si','`((?$1', '$1'); 54 | return preg_replace($find,$replace,$out); 55 | } 56 | ?> 57 | 58 |
    59 |
    60 |

    61 | Close 62 |

    63 |
    64 |
    65 |
    66 | 67 |
    68 |
    69 | « Back to 70 | 77 |
    78 |
    79 |
    80 |

    81 |

    82 | 83 | 84 | 85 | 86 | 87 | 96 | 97 |
    To:displayNumber ?> 88 | Call 89 | 95 |
    98 |
    99 |
    100 |

    101 |
    102 | from == 'Me:' ) {?> 105 |

    ".$msghistory->from ."
    ". MakeUrls($msghistory->text) ."
    ".$msghistory->time ."" ?>

    106 | 107 | 108 |

    ".$msghistory->from ."
    ". MakeUrls($msghistory->text) ."
    ".$msghistory->time ."" ?>

    109 | 110 | " : (($_SESSION['pidcommand'] == "Voicemail") ? "" : "

    No Messages!

    " ); 114 | } ?> 115 |
    116 |
    117 |
    118 |
    119 | 120 |
    121 |
    122 |
    123 |

    124 | 125 | 126 | " /> 127 | 128 | 129 |

    characters left

    130 | 131 | ... 132 |
    133 |
      134 |
    135 |
    136 |
    137 | 138 |
    139 | « Back to 140 | 141 |
    142 | 143 |
    144 | 145 | 146 | 149 | -------------------------------------------------------------------------------- /gvdetails.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | import json 5 | 6 | voice = Voice() 7 | try: 8 | email = argv[1] 9 | except: 10 | print ('Error! Please provide Email Account. ') 11 | exit(0) 12 | try: 13 | password = argv[2] 14 | except: 15 | print ('Error! Please provide Passsword. ') 16 | exit(0) 17 | try: 18 | voice.login(email,password) 19 | except: 20 | print ('Error! Login failed. ') 21 | exit(0) 22 | 23 | try: 24 | command = argv[3] 25 | except: 26 | print ('Error! Please provide a COMMAND. ') 27 | voice.logout() 28 | exit(0) 29 | 30 | try: 31 | ID = argv[4] 32 | except: 33 | print ('Error! Please provide a Message ID or Phone Number. ') 34 | voice.logout() 35 | exit(0) 36 | 37 | if command == "Inbox" : 38 | folder = voice.inbox().messages 39 | foundmsg = [ msg for msg in folder] 40 | elif command == "Voicemail" : 41 | folder = voice.voicemail().messages 42 | foundmsg = [ msg for msg in folder] 43 | elif command == "Recorded" : 44 | folder = voice.recorded().messages 45 | foundmsg = [ msg for msg in folder] 46 | elif command == "Messages" : 47 | folder = voice.sms().messages 48 | foundmsg = [ msg for msg in folder] 49 | elif command == "All" : 50 | folder = voice.all().messages 51 | foundmsg = [ msg for msg in folder] 52 | elif command == "Spam" : 53 | folder = voice.spam().folder 54 | foundmsg = [ msg for msg in folder.messages] 55 | elif command == "Trash" : 56 | folder = voice.trash().folder 57 | foundmsg = [ msg for msg in folder.messages] 58 | elif command == "Placed" : 59 | folder = voice.placed().messages 60 | foundmsg = [ msg for msg in folder] 61 | elif command == "Received" : 62 | folder = voice.received().messages 63 | foundmsg = [ msg for msg in folder] 64 | elif command == "Missed" : 65 | folder = voice.missed().messages 66 | foundmsg = [ msg for msg in folder] 67 | elif command == "Phone" : 68 | folder = voice.search(ID).messages 69 | foundmsg = [dict(msg) for msg in folder if (msg.messageText != "")] 70 | getID = [ msg.id for msg in folder if (msg.messageText != "")] 71 | ID = ''.join(getID) 72 | foundmsg = folder 73 | 74 | try: 75 | for message in foundmsg: 76 | if message.id == ID : 77 | message.mark() 78 | print json.dumps(message, indent=4, default=str) 79 | break 80 | except: 81 | print ('Error! With Message ID. ') 82 | 83 | voice.logout() 84 | -------------------------------------------------------------------------------- /gvhistory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | import BeautifulSoup, json 5 | 6 | def extractdata(htmldata) : 7 | """ 8 | extractdata -- extract DATA messages from BeautifulSoup tree of Google Voice Output in HTML. 9 | 10 | Output is a list of dictionaries, one per message. 11 | """ 12 | msgitems = [] 13 | tree = BeautifulSoup.BeautifulSoup(htmldata) 14 | conversations = tree.findAll("div",attrs={"id" : True}, recursive=False) 15 | for conversation in conversations : 16 | rows = conversation.findAll(attrs={"class" : "gc-message-sms-row"}) 17 | for row in rows : 18 | msgitem = {"id" : conversation["id"]} 19 | spans = row.findAll("span",attrs={"class" : True}, recursive=False) 20 | for span in spans : 21 | cl = span["class"].replace('gc-message-sms-', '') 22 | msgitem[cl] = (" ".join(span.findAll(text=True))).strip() 23 | msgitems.append(msgitem) 24 | return msgitems 25 | 26 | voice = Voice() 27 | try: 28 | email = argv[1] 29 | except: 30 | print ('Error! Please provide Email Account. ') 31 | exit(0) 32 | try: 33 | password = argv[2] 34 | except: 35 | print ('Error! Please provide Passsword. ') 36 | exit(0) 37 | try: 38 | voice.login(email,password) 39 | except: 40 | print ('Error! Login failed. ') 41 | exit(0) 42 | 43 | try: 44 | command = argv[3] 45 | except: 46 | print ('Error! Please provide a FOLDER. ') 47 | voice.logout() 48 | exit(0) 49 | 50 | try: 51 | ID = argv[4] 52 | except: 53 | print ('Error! Please provide a Message ID. ') 54 | voice.logout() 55 | exit(0) 56 | 57 | if command == "Inbox" : 58 | voice.inbox() 59 | allmessages = extractdata(voice.inbox.html) 60 | elif command == "Voicemail" : 61 | voice.voicemail() 62 | allmessages = extractdata(voice.voicemail.html) 63 | elif command == "Recorded" : 64 | voice.recorded() 65 | allmessages = extractdata(voice.recorded.html) 66 | elif command == "Messages" : 67 | voice.sms() 68 | allmessages = extractdata(voice.sms.html) 69 | elif command == "All" : 70 | voice.all() 71 | allmessages = extractdata(voice.all.html) 72 | elif command == "Spam" : 73 | voice.spam() 74 | allmessages = extractdata(voice.spam.html) 75 | elif command == "Trash" : 76 | voice.trash() 77 | allmessages = extractdata(voice.trash.html) 78 | elif command == "Placed" : 79 | voice.placed() 80 | allmessages = extractdata(voice.placed.html) 81 | elif command == "Received" : 82 | voice.received() 83 | allmessages = extractdata(voice.received.html) 84 | elif command == "Missed" : 85 | voice.missed() 86 | allmessages = extractdata(voice.missed.html) 87 | 88 | if allmessages != []: 89 | foundmsg = [msg for msg in allmessages if (msg['id'] == unicode(ID))] 90 | 91 | if foundmsg != []: 92 | foundmsg.sort(key=lambda x:x['time'], reverse=False) 93 | print json.dumps(foundmsg, indent=4, default=str) 94 | else: 95 | print ('Nothing found! ') 96 | 97 | voice.logout() 98 | -------------------------------------------------------------------------------- /gvmessages.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | import json 5 | 6 | voice = Voice() 7 | try: 8 | email = argv[1] 9 | except: 10 | print ('Error! Please provide Email Account. ') 11 | exit(0) 12 | try: 13 | password = argv[2] 14 | except: 15 | print ('Error! Please provide Passsword. ') 16 | exit(0) 17 | try: 18 | voice.login(email,password) 19 | except: 20 | print ('Error! Login failed. ') 21 | exit(0) 22 | 23 | try: 24 | command = argv[3] 25 | except: 26 | print ('Error! Please provide a phone number or FOLDER. ') 27 | voice.logout() 28 | exit(0) 29 | 30 | if command == "Inbox" : 31 | folder = voice.inbox().messages 32 | foundmsg = [ msg for msg in folder] 33 | elif command == "Messages" : 34 | folder = voice.sms().messages 35 | foundmsg = [ msg for msg in folder] 36 | elif command == "All" : 37 | voice.all() 38 | folder = voice.all.folder 39 | foundmsg = [ msg for msg in folder.messages] 40 | elif command == "Spam" : 41 | voice.spam() 42 | folder = voice.spam.folder 43 | foundmsg = [ msg for msg in folder.messages] 44 | elif command == "Trash" : 45 | voice.trash() 46 | folder = voice.trash.folder 47 | foundmsg = [ msg for msg in folder.messages] 48 | elif command == "Placed" : 49 | folder = voice.placed().messages 50 | foundmsg = [ msg for msg in folder] 51 | elif command == "Received" : 52 | voice.received() 53 | folder = voice.received.messages 54 | foundmsg = [ msg for msg in folder] 55 | elif command == "Missed" : 56 | folder = voice.missed().messages 57 | foundmsg = [ msg for msg in folder] 58 | #elif command == "History" : 59 | #try: 60 | #phone = argv[4] 61 | #folder = voice.search(phone) 62 | #foundmsg = [ msg for msg in folder.messages if (msg.messageText != "") ] 63 | #except: 64 | #print ('Error! Please provide a phone number. ') 65 | #voice.logout() 66 | #exit(0) 67 | else: 68 | folder = voice.search(command) 69 | foundmsg = [ msg for msg in folder.messages] 70 | 71 | if foundmsg != []: 72 | foundmsg.sort(key=lambda x:x['displayStartDateTime'], reverse=True) 73 | print json.dumps(foundmsg, indent=4, default=str) 74 | else: 75 | print('Nothing found! ') 76 | 77 | voice.logout() 78 | -------------------------------------------------------------------------------- /gvping.php: -------------------------------------------------------------------------------- 1 | checksetting("UNREAD"); 9 | if (($unreadCounts->unread) > 0) { 10 | echo "unread."\">Unread Voice Messages."; 11 | } 12 | } 13 | 14 | switch($command) { 15 | case "checkgoogle": 16 | checkgoogle(); 17 | break; 18 | } 19 | ?> -------------------------------------------------------------------------------- /gvrecorded-mp3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | from os import path, makedirs 5 | import json 6 | 7 | voice = Voice() 8 | try: 9 | email = argv[1] 10 | except: 11 | print ('Error! Please provide Email Account.') 12 | exit(0) 13 | 14 | try: 15 | password = argv[2] 16 | except: 17 | print ('Error! Please provide Passsword.') 18 | exit(0) 19 | 20 | try: 21 | voice.login(email,password) 22 | except: 23 | print ('Error! Login failed.') 24 | exit(0) 25 | 26 | try: 27 | for message in voice.recorded().messages: 28 | directory = "googlerecorded/" + message.id 29 | if not path.isdir(directory): 30 | makedirs(directory) 31 | message.download(directory) 32 | folder = voice.recorded().messages 33 | foundmsg = [ msg for msg in folder] 34 | if foundmsg != []: 35 | foundmsg.sort(key=lambda x:x['displayStartDateTime'], reverse=True) 36 | print json.dumps(foundmsg, indent=4, default=str) 37 | except: 38 | print ("Error! Recordings not downloaded.") 39 | 40 | voice.logout 41 | -------------------------------------------------------------------------------- /gvsendsms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | import json, re 5 | 6 | voice = Voice() 7 | try: 8 | email = argv[1] 9 | except: 10 | print ('Error! Please provide Email Account.') 11 | exit(0) 12 | 13 | try: 14 | password = argv[2] 15 | except: 16 | print ('Error! Please provide Passsword.') 17 | exit(0) 18 | 19 | try: 20 | voice.login(email,password) 21 | except: 22 | print ('Error! Login failed.') 23 | exit(0) 24 | 25 | try: 26 | phoneNumber = re.sub(r'\D', '', argv[3]).lstrip('1') 27 | except: 28 | print ('Error! Please provide a phone number') 29 | voice.logout() 30 | exit(0) 31 | 32 | try: 33 | text = json.loads(argv[4]) 34 | except: 35 | print ('Error! Please provide a message') 36 | voice.logout() 37 | exit(0) 38 | 39 | try: 40 | voice.send_sms(phoneNumber, text) 41 | print ('Message Sent') 42 | except: 43 | print ('Error! Message not sent') 44 | 45 | voice.logout() 46 | -------------------------------------------------------------------------------- /gvsettingcheck.php: -------------------------------------------------------------------------------- 1 | \n"; 23 | file_put_contents($filename, $configurationData, LOCK_EX); 24 | } 25 | require("$filename"); 26 | require_once("header.php"); 27 | ?> 28 | 29 | 30 |
    31 |
    32 |
    33 | checksetting("SETTING"); 37 | $phoneresults = $google->checksetting("PHONES"); 38 | echo "
    Inbox "; 39 | echo " Messages "; 40 | echo " Voicemail "; 41 | echo " Recorded "; 42 | echo " Missed "; 43 | echo " Placed "; 44 | echo " Received "; 45 | echo " Spam "; 46 | echo " Trash "; 47 | echo " Setting
    "; 48 | ?> 49 |
    50 | 51 |
    52 |
    Google Voice Login: 53 |
    54 | 55 |
    58 |
    61 | 62 | 63 |

    Once you get this set up you'll need to perform these two additional steps.

    After first logging into your Google account with a browser using the same IP address as accessing your Web server:

    (1) Enable Less Secure Apps and
    (2) Activate the Google Voice Reset Procedure

    Now promptly send an SMS message from your Web server. Once these steps are done click on the links above to display messages in your Google Voice Account. 64 |
    65 |
    > 66 |

    Theme

    67 |
    68 | 69 |
    70 | 77 |
    78 | 79 |

    Phones

    80 |
    81 | 95 |
    96 |
    98 | 99 | 100 | Your Voice Number: ".$settingresults->primaryDidInfo->formattedNumber; 102 | echo " Credits: ".$settingresults->credits; 103 | echo "
    SMS Notifications:
    "; 104 | if (is_array($settingresults->smsNotifications)) { 105 | foreach ($settingresults->smsNotifications as $smsAddress) { 106 | echo " ' : ' Active: No' ; 108 | } 109 | } else { 110 | echo " ' : ' Active: No' ; 112 | } 113 | echo "Email Notification Address: ".$settingresults->emailNotificationAddress."
    "; 114 | ?> 115 |

    Phone Setting

    116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 139 | 140 | 141 | 142 | 143 | 144 |
    NameNumberSMS ForwardingVoicemail ForwardingCarrier
    name; ?>formattedNumber; ?>smsEnabled=="true") ? 'Yes' : 'No' ); ?>redirectToVoicemail=="true") ? 'Yes' : 'No' ); ?>carrier; ?>
    145 | 146 | 147 | -------------------------------------------------------------------------------- /gvsettingcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice, settings 4 | import json 5 | 6 | voice = Voice() 7 | try: 8 | email = argv[1] 9 | except: 10 | print ('Error! Please provide Email Account. ') 11 | exit(0) 12 | try: 13 | password = argv[2] 14 | except: 15 | print ('Error! Please provide Passsword. ') 16 | exit(0) 17 | try: 18 | voice.login(email,password) 19 | except: 20 | print ('Error! Login failed. ') 21 | exit(0) 22 | 23 | try: 24 | command = argv[3] 25 | except: 26 | print ('Error! Please provide COMMAND. ') 27 | voice.logout() 28 | exit(0) 29 | 30 | data = voice.all() 31 | if command == "SETTING": 32 | print json.dumps(voice.settings, indent=4, default=str) 33 | if command == "PHONES": 34 | print json.dumps(voice.phones, indent=4, default=str) 35 | if command == "UNREAD": 36 | print json.dumps(data.unreadCounts, indent=4, default=str) 37 | 38 | voice.logout() 39 | -------------------------------------------------------------------------------- /gvvoicemail-mp3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit, argv 3 | from googlevoice import Voice 4 | from os import path, makedirs 5 | import json 6 | 7 | voice = Voice() 8 | try: 9 | email = argv[1] 10 | except: 11 | print ('Error! Please provide Email Account.') 12 | exit(0) 13 | 14 | try: 15 | password = argv[2] 16 | except: 17 | print ('Error! Please provide Passsword.') 18 | exit(0) 19 | 20 | try: 21 | voice.login(email,password) 22 | except: 23 | print ('Error! Login failed.') 24 | exit(0) 25 | 26 | try: 27 | for message in voice.voicemail().messages: 28 | directory = "googlevoicemail/" + message.id 29 | if not path.isdir(directory): 30 | makedirs(directory) 31 | message.download(directory) 32 | folder = voice.voicemail().messages 33 | foundmsg = [ msg for msg in folder] 34 | if foundmsg != []: 35 | foundmsg.sort(key=lambda x:x['displayStartDateTime'], reverse=True) 36 | print json.dumps(foundmsg, indent=4, default=str) 37 | except: 38 | print ("Error! Voicemails not downloaded.") 39 | 40 | voice.logout -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 22 | Mini Google Voice - Addon App 23 | 24 | 25 | 26 |

    Voice

    27 |
    28 |
    29 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /pygooglevoice/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, Joe McCall & Justin Quick 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the authors nor the names of its 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /pygooglevoice/README: -------------------------------------------------------------------------------- 1 | Python Google Voice 2 | ==================== 3 | 4 | Joe McCall & Justin Quick 5 | 6 | Exposing the Google Voice "API" to the Python language 7 | ------------------------------------------------------- 8 | 9 | Google Voice for Python Allows you to place calls, send sms, download voicemail, and check the various folders of your Google Voice Accounts. 10 | You can use the Python API or command line script to schedule calls, check for new recieved calls/sms, or even sync your recorded voicemails/calls. 11 | Works for Python 2 and Python 3 12 | 13 | Full documentation is available up at http://sphinxdoc.github.com/pygooglevoice/ 14 | -------------------------------------------------------------------------------- /pygooglevoice/README.rst: -------------------------------------------------------------------------------- 1 | Python Google Voice 2 | ==================== 3 | 4 | Joe McCall & Justin Quick 5 | 6 | Exposing the Google Voice "API" to the Python language 7 | ------------------------------------------------------- 8 | 9 | Google Voice for Python Allows you to place calls, send sms, download voicemail, and check the various folders of your Google Voice Accounts. 10 | You can use the Python API or command line script to schedule calls, check for new recieved calls/sms, or even sync your recorded voicemails/calls. 11 | Works for Python 2 and Python 3 12 | 13 | Full documentation is available up at http://sphinxdoc.github.com/pygooglevoice/ 14 | -------------------------------------------------------------------------------- /pygooglevoice/bin/asterisk-gvoice-setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Jacob Feisley, Ward Mundy, and Justin Quick 4 | """ 5 | from sys import exit 6 | from getpass import getpass 7 | from googlevoice.util import input, print_ 8 | 9 | print_("""This script installs Google Voice support on your PBX. 10 | You must have a system that is compatible with PBX in a Flash. 11 | WARNING: No error checking is provided. 12 | By using this script, you agree to assume ALL RISK. 13 | NO WARRANTY, EXPRESS OR IMPLIED, OF ANY KIND IS PROVIDED. 14 | 15 | If you make a typo while entering values below, press Ctrl-C and start over. 16 | Before starting, make sure you have removed any original [custom-gv] context 17 | """) 18 | 19 | conf_default = '/etc/asterisk/extensions_custom.conf' 20 | conf = input("""Asterisk dialplan configuration file 21 | [Default %s]: """ % conf_default) 22 | 23 | if not conf.strip(): 24 | conf = conf_default 25 | 26 | print_(""" 27 | Your Google Voice entries are stored in %s 28 | Edit that file and reload your Asterisk dialplan if you make future changes. 29 | """ % conf) 30 | 31 | settings = { 32 | 'config': conf, 33 | 'gvnum': input("10-digit Google Voice phone number (e.g. 9871234567): "), 34 | 'acctname': input("Google Voice email address: "), 35 | 'acctpass': getpass("Google Voice password: "), 36 | 'ringback': input("11-digit Ring Back DID (e.g. 16781234567): "), 37 | 'callpark': input("Parking Lot Magic Number: "), 38 | } 39 | 40 | 41 | input(""" 42 | We are now ready to begin the installation. 43 | Confirm your entries below or press Ctrl-C to abort and try again. 44 | 45 | CONFIG: %(config)s 46 | GVNUM: %(gvnum)s 47 | ACCTNAME: %(acctname)s 48 | RINGBACK: %(ringback)s 49 | CALLPARK: %(callpark)s 50 | 51 | Hit Enter key to proceed 52 | """ % settings) 53 | 54 | print_(""" 55 | Installing Google Voice support for your PBX. One moment please... 56 | """) 57 | 58 | content = """ 59 | [custom-gv] 60 | exten => _X.,1,Wait(1) 61 | exten => _X.,n,Set(ACCTNAME=%(acctname)s) 62 | exten => _X.,n,Set(ACCTPASS=%(acctpass)s) 63 | exten => _X.,n,Set(RINGBACK=%(ringback)s) 64 | exten => _X.,n,Set(CALLPARK=%(callpark)s) 65 | exten => _X.,n,Playback(pls-wait-connect-call) 66 | exten => _X.,n,System(gvoice -b -e \${ACCTNAME} -p \${ACCTPASS} call \${EXTEN} \${RINGBACK}) 67 | exten => _X.,n,Set(PARKINGEXTEN=\${CALLPARK}) 68 | exten => _X.,n,Park() 69 | exten => _X.,n,ParkAndAnnounce(pbx-transfer:PARKED|45|Console/dsp) 70 | 71 | [custom-park] 72 | exten => s,1,Wait(4) 73 | exten => s,2,Set(GVNUM=%(gvnum)s) 74 | exten => s,3,Set(CALLPARK=%(callpark)s) 75 | exten => s,4,NoOp(**CALLERID: \${CALLERID(number)}) 76 | exten => s,5,GotoIf($["${CALLERID(number)}"="${GVNUM}"]?6:7) 77 | exten => s,6,ParkedCall(\${CALLPARK}) 78 | exten => s,7,Goto(from-trunk,gv-incoming,1) 79 | 80 | """ 81 | 82 | try: 83 | fo = open(conf, 'a') 84 | fo.write(content % settings) 85 | fo.close() 86 | except IOError: 87 | print_('Error opening file for writing: %s' % conf) 88 | exit(0) 89 | 90 | print_(""" 91 | Installation script is finished. Do NOT run it again on this system! 92 | 93 | You can now reload your Asterisk dialplan configuration with the following command 94 | 95 | asterisk -rx "dialplan reload" 96 | 97 | For complete documentation, see the following Nerd Vittles article: 98 | 99 | http://nerdvittles.com/?p=635 100 | """) 101 | -------------------------------------------------------------------------------- /pygooglevoice/bin/gvi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple script to startup a python interpreter after logging into the voice service 5 | local variable `voice` is set as the main Voice instance 6 | """ 7 | import code 8 | from googlevoice import Voice 9 | 10 | voice = Voice() 11 | voice.login() 12 | 13 | code.interact(banner=""" 14 | You are now using Google Voice in the interactive python shell 15 | Try 'help(voice)' for more info 16 | """,local={'voice':voice}) -------------------------------------------------------------------------------- /pygooglevoice/bin/gvoice: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from sys import exit 3 | from atexit import register 4 | from optparse import OptionParser 5 | from googlevoice.voice import Voice 6 | from googlevoice.util import LoginError,pprint,input,print_ 7 | 8 | parser = OptionParser(usage='''gvoice [options] commands 9 | Where commands are 10 | 11 | login (li) - log into the voice service 12 | logout (lo) - log out of the service and make sure session is deleted 13 | help 14 | 15 | Voice Commands 16 | call (c) - call an outgoing number from a forwarding number 17 | cancel (cc) - cancel a particular call 18 | download (d) - download mp3 message given id hash 19 | send_sms (s) - send sms messages 20 | 21 | Folder Views 22 | search (se) 23 | inbox (i) 24 | voicemail (v) 25 | starred (st) 26 | all (a) 27 | spam (sp) 28 | trash (t) 29 | voicemail (v) 30 | sms (sm) 31 | recorded (r) 32 | placed (p) 33 | recieved (re) 34 | missed (m)''') 35 | parser.add_option("-e", "--email", dest="email", default=None, 36 | help="Google Voice Account Email") 37 | parser.add_option("-p", "--password", dest='passwd', default=None, 38 | help='Your account password (prompted if blank)') 39 | parser.add_option("-b", "--batch", dest='batch', default=False, action="store_true", 40 | help='Batch operations, asking for no interactive input') 41 | options, args = parser.parse_args() 42 | 43 | def login(email=options.email, passwd=options.passwd, batch=options.batch): 44 | """ 45 | Login Voice instance based on options and interactivity 46 | """ 47 | global voice 48 | try: 49 | voice.login(options.email,options.passwd) 50 | except LoginError: 51 | if batch: 52 | print_('Login failed.') 53 | exit(0) 54 | if input('Login failed. Retry?[Y/n] ').lower() in ('', 'y'): 55 | login(None, None, batch) 56 | else: 57 | exit(0) 58 | 59 | def logout(): 60 | global voice 61 | print_('Logging out of voice...') 62 | voice.logout() 63 | 64 | def pprint_folder(name): 65 | folder = getattr(voice, name)() 66 | print_(folder) 67 | pprint(folder.messages,indent=4) 68 | 69 | try: 70 | action,args = args[0],args[1:] 71 | except IndexError: 72 | action = 'interactive' 73 | 74 | if action == 'help': 75 | print_(parser.usage) 76 | exit(0) 77 | 78 | voice = Voice() 79 | login() 80 | 81 | register(logout) 82 | 83 | if action == 'interactive': 84 | while 1: 85 | try: 86 | action = input('gvoice> ').lower().strip() 87 | except (EOFError, KeyboardInterrupt): 88 | exit(0) 89 | if not action: continue 90 | elif action in ('q','quit','exit'): break 91 | elif action in ('login','li'): login() 92 | elif action in ('logout','lo'): voice.logout() 93 | elif action in ('call','c'): 94 | voice.call( 95 | input('Outgoing number: '), 96 | input('Forwarding number [optional]: ') or None, 97 | int(input('Phone type [1-Home, 2-Mobile, 3-Work, 7-Gizmo]:') or 2) 98 | ) 99 | print_('Calling...') 100 | elif action in ('cancelcall','cc'): voice.cancel() 101 | elif action in ('sendsms','s'): 102 | voice.send_sms(input('Phone number: '), input('Message: ')) 103 | print_('Message Sent') 104 | elif action in ('search','se'): 105 | se=voice.search(input('Search query: ')) 106 | print_(se) 107 | pprint(se.messages) 108 | elif action in ('download','d'): 109 | print_('MP3 downloaded to %s' % voice.download(input('Message sha1: '))) 110 | elif action in ('help','h','?'): print_(parser.usage) 111 | elif action in ('trash','t'): pprint_folder('trash') 112 | elif action in ('spam','sp'): pprint_folder('spam') 113 | elif action in ('inbox','i'): pprint_folder('inbox') 114 | elif action in ('voicemail','v'): pprint_folder('voicemail') 115 | elif action in ('all','a'): pprint_folder('all') 116 | elif action in ('starred','st'): pprint_folder('starred') 117 | elif action in ('missed','m'): pprint_folder('missed') 118 | elif action in ('recieved','re'): pprint_folder('recieved') 119 | elif action in ('recorded','r'): pprint_folder('recorded') 120 | elif action in ('sms','sm'): pprint_folder('sms') 121 | else: 122 | if action == 'send_sms': 123 | try: 124 | num,args = args[0],args[1:] 125 | except: 126 | print_('Please provide a message') 127 | exit(0) 128 | args = (num, ' '.join(args)) 129 | getattr(voice,action)(*args) -------------------------------------------------------------------------------- /pygooglevoice/build/lib/googlevoice/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This project aims to bring the power of the Google Voice API to the Python language in a simple, 3 | easy-to-use manner. Currently it allows you to place calls, send sms, 4 | download voicemails/recorded messages, and search the various folders of your Google Voice Accounts. 5 | You can use the Python API or command line script to schedule calls, check for new received calls/sms, 6 | or even sync your recorded voicemails/calls. 7 | Works for Python 2 and Python 3 8 | 9 | """ 10 | __author__ = 'Justin Quick and Joe McCall' 11 | __email__ = 'justquick@gmail.com, joe@mcc4ll.us', 12 | __copyright__ = 'Copyright 2009, Justin Quick and Joe McCall' 13 | __credits__ = ['Justin Quick','Joe McCall','Jacob Feisley','John Nagle'] 14 | __license__ = 'New BSD' 15 | __version__ = '0.5' 16 | 17 | from voice import Voice 18 | from util import Phone, Message, Folder -------------------------------------------------------------------------------- /pygooglevoice/build/lib/googlevoice/conf.py: -------------------------------------------------------------------------------- 1 | from ConfigParser import ConfigParser, NoOptionError 2 | import os 3 | import settings 4 | 5 | 6 | class Config(ConfigParser): 7 | """ 8 | ``ConfigParser`` subclass that looks into your home folder for a file named 9 | ``.gvoice`` and parses configuration data from it. 10 | """ 11 | def __init__(self): 12 | self.fname = os.path.expanduser('~/.gvoice') 13 | 14 | if not os.path.exists(self.fname): 15 | try: 16 | with open(self.fname, 'w') as f: 17 | f.write(settings.DEFAULT_CONFIG) 18 | except IOError: 19 | return 20 | 21 | ConfigParser.__init__(self) 22 | 23 | try: 24 | self.read([self.fname]) 25 | except IOError: 26 | return 27 | 28 | def get(self, option, section='gvoice'): 29 | try: 30 | return ConfigParser.get(self, section, option).strip() or None 31 | except NoOptionError: 32 | return 33 | 34 | def set(self, option, value, section='gvoice'): 35 | return ConfigParser.set(self, section, option, value) 36 | 37 | def phoneType(self): 38 | try: 39 | return int(self.get('phoneType')) 40 | except TypeError: 41 | return 42 | 43 | def save(self): 44 | with open(self.f, 'w') as f: 45 | f.write(f) 46 | 47 | phoneType = property(phoneType) 48 | forwardingNumber = property(lambda self: self.get('forwardingNumber')) 49 | email = property(lambda self: self.get('email', 'auth')) 50 | password = property(lambda self: self.get('password', 'auth')) 51 | smsKey = property(lambda self: self.get('smsKey', 'auth')) 52 | secret = property(lambda self: self.get('secret')) 53 | 54 | config = Config() 55 | -------------------------------------------------------------------------------- /pygooglevoice/build/lib/googlevoice/settings.py: -------------------------------------------------------------------------------- 1 | DEFAULT_CONFIG = """ 2 | [auth] 3 | # Google Account email address (one associated w/ your Voice account) 4 | email= 5 | 6 | # Raw password used or login 7 | password= 8 | 9 | # Optional 2-step authentication key (as provided by Google) 10 | smsKey= 11 | 12 | [gvoice] 13 | # Number to place calls from (eg, your google voice number) 14 | forwardingNumber= 15 | 16 | # Default phoneType for your forwardingNumber as defined below 17 | # 1 - Home 18 | # 2 - Mobile 19 | # 3 - Work 20 | # 7 - Gizmo 21 | # 9 - Googletalk 22 | phoneType=2 23 | """ 24 | 25 | TYPES = { 26 | 0: 'missed', 27 | 1: 'received', 28 | 2: 'voicemail', 29 | 4: 'recorded', 30 | 7: 'placed', 31 | 10: 'sms.received', 32 | 11: 'sms.sent' 33 | } 34 | 35 | DEBUG = False 36 | 37 | LOGIN = 'https://accounts.google.com/ServiceLogin?continue=https://www.google.com/voice&rip=1&nojavascript=1&followup=https://www.google.com/voice&service=grandcentral<mpl=open&rip=1&flowName=GlifWebSignIn&flowEntry=Identifier' 38 | #LOGIN = 'https://accounts.google.com/ServiceLogin?continue=https://www.google.com/voice&rip=1&nojavascript=1&followup=https://www.google.com/voice&service=grandcentral<mpl=open&flowName=GlifWebSignIn&flowEntry=Identifier' 39 | 40 | LOGIN_POST = 'https://accounts.google.com/signin/challenge/sl/password?service=grandcentral&continue=https://www.google.com/voice/redirection/voice&followup=https://www.google.com/voice<mpl=open' 41 | 42 | USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36' 43 | 44 | SMSAUTH = 'https://accounts.google.com/SmsAuth' 45 | FEEDS = ('inbox', 'starred', 'all', 'history', 'spam', 'trash', 'voicemail', 'sms', 46 | 'recorded', 'placed', 'received', 'missed') 47 | 48 | BASE = 'https://www.google.com/voice/b/0/' 49 | LOGOUT = 'https://www.google.com/voice/account/signout' 50 | INBOX = BASE + '#inbox' 51 | HISTORY = BASE + '#history' 52 | CALL = BASE + 'call/connect/' 53 | CANCEL = BASE + 'call/cancel/' 54 | DEFAULT_FORWARD = BASE + 'settings/editDefaultForwarding/' 55 | FORWARD = BASE + 'settings/editForwarding/' 56 | SMS_FORWARD = BASE + 'settings/editForwardingSms/' 57 | VOICEMAILNOTIFY = BASE + 'settings/editVoicemailSms/' 58 | ADDNOTE = BASE + 'inbox/savenote/' 59 | DELETENOTE = BASE + 'inbox/deletenote/' 60 | DELETE = BASE + 'inbox/deleteMessages/' 61 | ARCHIVE = BASE + 'inbox/archiveMessages/' 62 | MARK = BASE + 'inbox/mark/' 63 | STAR = BASE + 'inbox/star/' 64 | BLOCK = BASE + 'inbox/block/' 65 | SMS = BASE + 'sms/send/' 66 | DOWNLOAD = BASE + 'media/send_voicemail/' 67 | BALANCE = BASE + 'settings/billingcredit/' 68 | 69 | XML_SEARCH = BASE + 'inbox/search/' 70 | XML_CONTACTS = BASE + 'contacts/' 71 | XML_RECENT = BASE + 'inbox/recent/' 72 | XML_MESSAGE = BASE + 'inbox/message/' 73 | XML_INBOX = XML_RECENT + 'inbox/' 74 | XML_STARRED = XML_RECENT + 'starred/' 75 | XML_ALL = XML_RECENT + 'all/' 76 | XML_HISTORY = XML_RECENT + 'history/' 77 | XML_SPAM = XML_RECENT + 'spam/' 78 | XML_TRASH = XML_RECENT + 'trash/' 79 | XML_VOICEMAIL = XML_RECENT + 'voicemail/' 80 | XML_SMS = XML_RECENT + 'sms/' 81 | XML_RECORDED = XML_RECENT + 'recorded/' 82 | XML_PLACED = XML_RECENT + 'placed/' 83 | XML_RECEIVED = XML_RECENT + 'received/' 84 | XML_MISSED = XML_RECENT + 'missed/' 85 | -------------------------------------------------------------------------------- /pygooglevoice/build/lib/googlevoice/tests.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice, util 2 | from os import path, remove 3 | from unittest import TestCase, main 4 | 5 | class VoiceTest(TestCase): 6 | voice = Voice() 7 | voice.login() 8 | outgoing = util.input('Outgoing number (blank to ignore call tests): ') 9 | forwarding = None 10 | if outgoing: 11 | forwarding = util.input('Forwarding number [optional]: ') or None 12 | 13 | if outgoing: 14 | def test_1call(self): 15 | self.voice.call(self.outgoing, self.forwarding) 16 | 17 | def test_sms(self): 18 | self.voice.send_sms(self.outgoing, 'i sms u') 19 | 20 | def test_2cancel(self): 21 | self.voice.cancel(self.outgoing, self.forwarding) 22 | 23 | def test_special(self): 24 | self.assert_(self.voice.special) 25 | 26 | def test_inbox(self): 27 | self.assert_(self.voice.inbox) 28 | 29 | def test_balance(self): 30 | self.assert_(self.voice.settings['credits']) 31 | 32 | def test_search(self): 33 | self.assert_(len(self.voice.search('joe'))) 34 | 35 | def test_disable_enable(self): 36 | self.voice.phones[0].disable() 37 | self.voice.phones[0].enable() 38 | 39 | def test_download(self): 40 | msg = list(self.voice.voicemail.messages)[0] 41 | fn = '%s.mp3' % msg.id 42 | if path.isfile(fn): remove(fn) 43 | self.voice.download(msg) 44 | self.assert_(path.isfile(fn)) 45 | 46 | def test_zlogout(self): 47 | self.voice.logout() 48 | self.assert_(self.voice.special is None) 49 | 50 | def test_config(self): 51 | from conf import config 52 | self.assert_(config.forwardingNumber) 53 | self.assert_(str(config.phoneType) in '1237') 54 | self.assertEqual(config.get('wtf'), None) 55 | 56 | if __name__ == '__main__': main() -------------------------------------------------------------------------------- /pygooglevoice/docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | 15 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " pickle to make pickle files" 22 | @echo " json to make JSON files" 23 | @echo " htmlhelp to make HTML files and a HTML help project" 24 | @echo " qthelp to make HTML files and a qthelp project" 25 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 26 | @echo " changes to make an overview of all changed/added/deprecated items" 27 | @echo " linkcheck to check all external links for integrity" 28 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 29 | 30 | clean: 31 | -rm -rf $(BUILDDIR)/* 32 | 33 | html: 34 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 35 | @echo 36 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 37 | 38 | dirhtml: 39 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 40 | @echo 41 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 42 | 43 | pickle: 44 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 45 | @echo 46 | @echo "Build finished; now you can process the pickle files." 47 | 48 | json: 49 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 50 | @echo 51 | @echo "Build finished; now you can process the JSON files." 52 | 53 | htmlhelp: 54 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 55 | @echo 56 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 57 | ".hhp project file in $(BUILDDIR)/htmlhelp." 58 | 59 | qthelp: 60 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 61 | @echo 62 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 63 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 64 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyGoogleVoice.qhcp" 65 | @echo "To view the help file:" 66 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyGoogleVoice.qhc" 67 | 68 | latex: 69 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 70 | @echo 71 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 72 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 73 | "run these through (pdf)latex." 74 | 75 | changes: 76 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 77 | @echo 78 | @echo "The overview file is in $(BUILDDIR)/changes." 79 | 80 | linkcheck: 81 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 82 | @echo 83 | @echo "Link check complete; look for any errors in the above output " \ 84 | "or in $(BUILDDIR)/linkcheck/output.txt." 85 | 86 | doctest: 87 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 88 | @echo "Testing of doctests in the sources finished, look at the " \ 89 | "results in $(BUILDDIR)/doctest/output.txt." 90 | -------------------------------------------------------------------------------- /pygooglevoice/docs/api.txt: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | 4 | API Reference 5 | ============= 6 | 7 | .. automodule:: googlevoice 8 | 9 | Voice 10 | ------ 11 | 12 | In addition to the methods below, ``Voice`` instances have several special methods for 13 | gathering information from folders in the Google Voice service. These methods are: 14 | 15 | * ``inbox`` - Recent, unread messages 16 | * ``starred`` - Starred messages 17 | * ``all`` - All messages 18 | * ``spam`` - Messages likely to be spam 19 | * ``trash`` - Deleted messages 20 | * ``voicemail`` - Voicemail messages 21 | * ``sms`` - Text messages 22 | * ``recorded`` - Recorced messages 23 | * ``placed`` - Outgoing messages 24 | * ``received`` - Incoming messages 25 | * ``missed`` - Messages not received 26 | 27 | All of these special methods operate the same way. When they are called, 28 | they parse the feed from the Google Voice service and return a ``Folder`` instance. 29 | After they have been called, you can grab the JSON and HTML data directly. 30 | 31 | Usage:: 32 | 33 | >>> voice.inbox() # Parses feed and returns Folder instance 34 | ... 35 | >>> voice.inbox.json # Raw JSON data 36 | ... u'{"messages":{"14ef89...' 37 | >>> voice.inbox.html # Raw HTML data 38 | ... u'\n\n \n
    ' 43 | 44 | # The version info for the project you're documenting, acts as replacement for 45 | # |version| and |release|, also used in various other places throughout the 46 | # built documents. 47 | # 48 | # The short X.Y version. 49 | version = '0.5' 50 | # The full version, including alpha/beta/rc tags. 51 | release = '0.5' 52 | 53 | # The language for content autogenerated by Sphinx. Refer to documentation 54 | # for a list of supported languages. 55 | #language = None 56 | 57 | # There are two options for replacing |today|: either, you set today to some 58 | # non-false value, then it is used: 59 | #today = '' 60 | # Else, today_fmt is used as the format for a strftime call. 61 | #today_fmt = '%B %d, %Y' 62 | 63 | # List of documents that shouldn't be included in the build. 64 | #unused_docs = [] 65 | 66 | # List of directories, relative to source directory, that shouldn't be searched 67 | # for source files. 68 | exclude_trees = ['build'] 69 | 70 | # The reST default role (used for this markup: `text`) to use for all documents. 71 | #default_role = None 72 | 73 | # If true, '()' will be appended to :func: etc. cross-reference text. 74 | #add_function_parentheses = True 75 | 76 | # If true, the current module name will be prepended to all description 77 | # unit titles (such as .. function::). 78 | #add_module_names = True 79 | 80 | # If true, sectionauthor and moduleauthor directives will be shown in the 81 | # output. They are ignored by default. 82 | #show_authors = False 83 | 84 | # The name of the Pygments (syntax highlighting) style to use. 85 | pygments_style = 'sphinx' 86 | 87 | # A list of ignored prefixes for module index sorting. 88 | #modindex_common_prefix = [] 89 | 90 | 91 | # -- Options for HTML output --------------------------------------------------- 92 | 93 | # The theme to use for HTML and HTML Help pages. Major themes that come with 94 | # Sphinx are currently 'default' and 'sphinxdoc'. 95 | html_theme = 'default' 96 | 97 | # Theme options are theme-specific and customize the look and feel of a theme 98 | # further. For a list of options available for each theme, see the 99 | # documentation. 100 | #html_theme_options = {} 101 | 102 | # Add any paths that contain custom themes here, relative to this directory. 103 | #html_theme_path = [] 104 | 105 | # The name for this set of Sphinx documents. If None, it defaults to 106 | # " v documentation". 107 | #html_title = None 108 | 109 | # A shorter title for the navigation bar. Default is the same as html_title. 110 | #html_short_title = None 111 | 112 | # The name of an image file (relative to this directory) to place at the top 113 | # of the sidebar. 114 | #html_logo = None 115 | 116 | # The name of an image file (within the static path) to use as favicon of the 117 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 118 | # pixels large. 119 | #html_favicon = None 120 | 121 | # Add any paths that contain custom static files (such as style sheets) here, 122 | # relative to this directory. They are copied after the builtin static files, 123 | # so a file named "default.css" will overwrite the builtin "default.css". 124 | html_static_path = ['static'] 125 | 126 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 127 | # using the given strftime format. 128 | #html_last_updated_fmt = '%b %d, %Y' 129 | 130 | # If true, SmartyPants will be used to convert quotes and dashes to 131 | # typographically correct entities. 132 | #html_use_smartypants = True 133 | 134 | # Custom sidebar templates, maps document names to template names. 135 | #html_sidebars = {} 136 | 137 | # Additional templates that should be rendered to pages, maps page names to 138 | # template names. 139 | #html_additional_pages = {} 140 | 141 | # If false, no module index is generated. 142 | #html_use_modindex = True 143 | 144 | # If false, no index is generated. 145 | #html_use_index = True 146 | 147 | # If true, the index is split into individual pages for each letter. 148 | #html_split_index = False 149 | 150 | # If true, links to the reST sources are added to the pages. 151 | #html_show_sourcelink = True 152 | 153 | # If true, an OpenSearch description file will be output, and all pages will 154 | # contain a tag referring to it. The value of this option must be the 155 | # base URL from which the finished HTML is served. 156 | #html_use_opensearch = '' 157 | 158 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 159 | #html_file_suffix = '' 160 | 161 | # Output file base name for HTML help builder. 162 | htmlhelp_basename = 'PyGoogleVoicedoc' 163 | 164 | 165 | # -- Options for LaTeX output -------------------------------------------------- 166 | 167 | # The paper size ('letter' or 'a4'). 168 | #latex_paper_size = 'letter' 169 | 170 | # The font size ('10pt', '11pt' or '12pt'). 171 | #latex_font_size = '10pt' 172 | 173 | # Grouping the document tree into LaTeX files. List of tuples 174 | # (source start file, target name, title, author, documentclass [howto/manual]). 175 | latex_documents = [ 176 | ('index', 'PyGoogleVoice.tex', u'PyGoogleVoice Documentation', 177 | u'Justin Quick \\textless{}justquick@gmail.com\\textgreater{}', 'manual'), 178 | ] 179 | 180 | # The name of an image file (relative to this directory) to place at the top of 181 | # the title page. 182 | #latex_logo = None 183 | 184 | # For "manual" documents, if this is true, then toplevel headings are parts, 185 | # not chapters. 186 | #latex_use_parts = False 187 | 188 | # Additional stuff for the LaTeX preamble. 189 | #latex_preamble = '' 190 | 191 | # Documents to append as an appendix to all manuals. 192 | #latex_appendices = [] 193 | 194 | # If false, no module index is generated. 195 | #latex_use_modindex = True 196 | -------------------------------------------------------------------------------- /pygooglevoice/docs/config.txt: -------------------------------------------------------------------------------- 1 | .. _config: 2 | 3 | 4 | Configuration 5 | ============= 6 | 7 | When you first install the module, it places an ini configuration 8 | file in yournamed ``.gvoice`` in your home directory. This runs the ``gvoice`` 9 | and other scripts with your personal configuration defined in this file. 10 | Run by default, these parameters are prompted for. 11 | Edit this file and fill in your personal configuration information. 12 | If you enter your ``password``, it must be raw text so watch the privileges on this file. 13 | 14 | 15 | Settings by Section 16 | --------------------- 17 | 18 | auth 19 | ^^^^ 20 | 21 | Login credentials for http://google.com/voice 22 | 23 | **email** 24 | 25 | The Google email account associated with Voice. Can be a gmail username, or proper email address. 26 | 27 | **password** 28 | 29 | Raw password for logging in. 30 | 31 | gvoice 32 | ^^^^^^^ 33 | 34 | **forwardingNumber** 35 | 36 | The number that you make your calls on (eg your Google Voice number) 37 | 38 | **phoneType** 39 | 40 | The type of device connected to your ``forwardingNumber``. Options are:: 41 | 42 | 1. Home 43 | 2. Mobile 44 | 3. Work 45 | 7. Gizmo 46 | 47 | Defaults to ``Mobile`` 48 | -------------------------------------------------------------------------------- /pygooglevoice/docs/examples.txt: -------------------------------------------------------------------------------- 1 | .. _examples: 2 | 3 | 4 | Examples 5 | ========= 6 | 7 | All of these can be found in the examples directory 8 | 9 | Place calls 10 | -------------- 11 | .. literalinclude:: ../examples/call.py 12 | 13 | Download MP3s 14 | ------------- 15 | .. literalinclude:: ../examples/download-mp3.py 16 | 17 | Send SMS messages 18 | ------------------ 19 | .. literalinclude:: ../examples/sms.py 20 | 21 | ``Phones`` 22 | ----------- 23 | .. literalinclude:: ../examples/phones.py 24 | 25 | ``Folders`` 26 | ------------ 27 | .. literalinclude:: ../examples/folders.py 28 | 29 | Search 30 | ------ 31 | .. literalinclude:: ../examples/search.py 32 | 33 | List voicemails 34 | ---------------- 35 | .. literalinclude:: ../examples/voicemail.py 36 | 37 | Delete ``Messages`` 38 | -------------------- 39 | .. literalinclude:: ../examples/delete.py 40 | 41 | Parse received SMS 42 | ------------------- 43 | .. literalinclude:: ../examples/parse_sms.py 44 | 45 | List account settings 46 | ---------------------- 47 | .. literalinclude:: ../examples/settings.py 48 | -------------------------------------------------------------------------------- /pygooglevoice/docs/index.txt: -------------------------------------------------------------------------------- 1 | .. _index: 2 | 3 | PyGoogleVoice Documentation 4 | ============================= 5 | 6 | :Authors: 7 | Justin Quick 8 | Joe McCall 9 | :Version: 0.5 10 | 11 | .. automodule:: googlevoice 12 | :members: 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | 17 | install 18 | config 19 | scripts 20 | examples 21 | api 22 | changelog 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` -------------------------------------------------------------------------------- /pygooglevoice/docs/install.txt: -------------------------------------------------------------------------------- 1 | .. _install: 2 | 3 | 4 | Installation 5 | ============= 6 | 7 | Requirements, setup instructions, and how to get it running with a PBX 8 | 9 | Requirements 10 | ------------------- 11 | 12 | * `Python >= 2.3 `_ 13 | * For Python < 2.6, gvoice requires `simplejson `_ 14 | 15 | Setups 16 | ------------------- 17 | 18 | Stable distribution setup:: 19 | 20 | $ yum install python python-setuptools 21 | $ sudo easy_install simplejson 22 | $ sudo easy_install -U pygooglevoice 23 | 24 | Bleeding edge source code setup:: 25 | 26 | $ yum install python python-setuptools mercurial 27 | $ sudo easy_install simplejson 28 | $ hg clone https://pygooglevoice.googlecode.com/hg/ pygooglevoice 29 | $ cd pygooglevoice 30 | $ sudo python setup.py install 31 | 32 | Asterisk Setup 33 | ------------------- 34 | 35 | Here is how to integrate Google Voice with a PBX. This guide was designed for `PBX in a flash `_, which is built upon `Asterisk `_ 36 | 37 | The first steps are to install `PBX in a flash `_. Here is a good guide for doing so http://knol.google.com/k/ward-mundy/pbx-in-a-flash/ 38 | 39 | Running the setup above copies over a setup script to integrate into your Asterisk configuration setup. Simply run ``$ asterisk-gvoice-setup`` answer a couple questions, then restart your PBX instance. -------------------------------------------------------------------------------- /pygooglevoice/docs/scripts.txt: -------------------------------------------------------------------------------- 1 | .. _scripts: 2 | 3 | 4 | Command Line Script 5 | =================== 6 | 7 | The module also comes with a script called ``gvoice`` which can do all the wonderful stuff that the 8 | Python module can do easily on the command line. 9 | 10 | 11 | Usage 12 | ----- 13 | 14 | :: 15 | 16 | Usage: gvoice [options] commands 17 | Where commands are 18 | 19 | login (li) - log into the voice service 20 | logout (lo) - log out of the service and make sure session is deleted 21 | help 22 | 23 | Voice Commands 24 | call (c) - call an outgoing number from a forwarding number 25 | cancel (cc) - cancel a particular call 26 | download (d) - download mp3 message given id hash 27 | send_sms (s) - send sms messages 28 | 29 | Folder Views 30 | search (se) 31 | inbox (i) 32 | voicemail (v) 33 | starred (st) 34 | all (a) 35 | spam (sp) 36 | trash (t) 37 | voicemail (v) 38 | sms (sm) 39 | recorded (r) 40 | placed (p) 41 | recieved (re) 42 | missed (m) 43 | 44 | Options: 45 | -h, --help show this help message and exit 46 | -e EMAIL, --email=EMAIL 47 | Google Voice Account Email 48 | -p PASSWD, --password=PASSWD 49 | Your account password (prompted if blank) 50 | -b, --batch Batch operations, asking for no interactive input 51 | 52 | 53 | Example 54 | ------- 55 | 56 | :: 57 | 58 | $ gvoice -e myusername@gmail.com 59 | Password: 60 | gvoice> call 61 | Outgoing number: 18004664411 62 | Forwarding number: 14075551234 63 | Calling... -------------------------------------------------------------------------------- /pygooglevoice/examples/call.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice 2 | from googlevoice.util import input 3 | 4 | voice = Voice() 5 | voice.login() 6 | 7 | outgoingNumber = input('Number to call: ') 8 | forwardingNumber = input('Number to call from [optional]: ') or None 9 | 10 | voice.call(outgoingNumber, forwardingNumber) 11 | 12 | if input('Calling now... cancel?[y/N] ').lower() == 'y': 13 | voice.cancel(outgoingNumber, forwardingNumber) -------------------------------------------------------------------------------- /pygooglevoice/examples/delete.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice 2 | 3 | voice = Voice() 4 | voice.login() 5 | 6 | for message in voice.sms().messages: 7 | if message.isRead: 8 | message.delete() -------------------------------------------------------------------------------- /pygooglevoice/examples/download-mp3.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice 2 | 3 | download_dir = '.' 4 | 5 | voice = Voice() 6 | voice.login() 7 | 8 | for message in voice.voicemail().messages: 9 | message.download(download_dir) -------------------------------------------------------------------------------- /pygooglevoice/examples/folders.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice,util,settings 2 | 3 | voice = Voice() 4 | voice.login() 5 | 6 | for feed in settings.FEEDS: 7 | util.print_(feed.title()) 8 | for message in getattr(voice, feed)().messages: 9 | util.print_('\t', message) -------------------------------------------------------------------------------- /pygooglevoice/examples/parse_sms.py: -------------------------------------------------------------------------------- 1 | # 2 | #SMS test via Google Voice 3 | # 4 | #John Nagle 5 | # nagle@animats.com 6 | # 7 | from googlevoice import Voice 8 | import sys 9 | import BeautifulSoup 10 | 11 | 12 | def extractsms(htmlsms) : 13 | """ 14 | extractsms -- extract SMS messages from BeautifulSoup tree of Google Voice SMS HTML. 15 | 16 | Output is a list of dictionaries, one per message. 17 | """ 18 | msgitems = [] # accum message items here 19 | # Extract all conversations by searching for a DIV with an ID at top level. 20 | tree = BeautifulSoup.BeautifulSoup(htmlsms) # parse HTML into tree 21 | conversations = tree.findAll("div",attrs={"id" : True},recursive=False) 22 | for conversation in conversations : 23 | # For each conversation, extract each row, which is one SMS message. 24 | rows = conversation.findAll(attrs={"class" : "gc-message-sms-row"}) 25 | for row in rows : # for all rows 26 | # For each row, which is one message, extract all the fields. 27 | msgitem = {"id" : conversation["id"]} # tag this message with conversation ID 28 | spans = row.findAll("span",attrs={"class" : True}, recursive=False) 29 | for span in spans : # for all spans in row 30 | cl = span["class"].replace('gc-message-sms-', '') 31 | msgitem[cl] = (" ".join(span.findAll(text=True))).strip() # put text in dict 32 | msgitems.append(msgitem) # add msg dictionary to list 33 | return msgitems 34 | 35 | voice = Voice() 36 | voice.login() 37 | 38 | voice.sms() 39 | for msg in extractsms(voice.sms.html): 40 | print str(msg) 41 | -------------------------------------------------------------------------------- /pygooglevoice/examples/phones.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice,util 2 | 3 | voice = Voice() 4 | voice.login() 5 | 6 | util.pprint(voice.phones) -------------------------------------------------------------------------------- /pygooglevoice/examples/search.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice,util 2 | 3 | 4 | voice = Voice() 5 | voice.login() 6 | 7 | folder = voice.search(util.input('Search query: ')) 8 | 9 | util.print_('Found %s messages: ', len(folder)) 10 | util.pprint(folder.messages) -------------------------------------------------------------------------------- /pygooglevoice/examples/settings.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice,util 2 | 3 | 4 | voice = Voice() 5 | voice.login() 6 | 7 | util.pprint(voice.settings) -------------------------------------------------------------------------------- /pygooglevoice/examples/sms.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice 2 | from googlevoice.util import input 3 | 4 | voice = Voice() 5 | voice.login() 6 | 7 | phoneNumber = input('Number to send message to: ') 8 | text = input('Message text: ') 9 | 10 | voice.send_sms(phoneNumber, text) -------------------------------------------------------------------------------- /pygooglevoice/examples/voicemail.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice,util 2 | 3 | voice = Voice() 4 | voice.login() 5 | 6 | for message in voice.voicemail().messages: 7 | util.print_(message) -------------------------------------------------------------------------------- /pygooglevoice/googlevoice/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This project aims to bring the power of the Google Voice API to the Python language in a simple, 3 | easy-to-use manner. Currently it allows you to place calls, send sms, 4 | download voicemails/recorded messages, and search the various folders of your Google Voice Accounts. 5 | You can use the Python API or command line script to schedule calls, check for new received calls/sms, 6 | or even sync your recorded voicemails/calls. 7 | Works for Python 2 and Python 3 8 | 9 | """ 10 | __author__ = 'Justin Quick and Joe McCall' 11 | __email__ = 'justquick@gmail.com, joe@mcc4ll.us', 12 | __copyright__ = 'Copyright 2009, Justin Quick and Joe McCall' 13 | __credits__ = ['Justin Quick','Joe McCall','Jacob Feisley','John Nagle'] 14 | __license__ = 'New BSD' 15 | __version__ = '0.5' 16 | 17 | from voice import Voice 18 | from util import Phone, Message, Folder -------------------------------------------------------------------------------- /pygooglevoice/googlevoice/conf.py: -------------------------------------------------------------------------------- 1 | from ConfigParser import ConfigParser, NoOptionError 2 | import os 3 | import settings 4 | 5 | 6 | class Config(ConfigParser): 7 | """ 8 | ``ConfigParser`` subclass that looks into your home folder for a file named 9 | ``.gvoice`` and parses configuration data from it. 10 | """ 11 | def __init__(self): 12 | self.fname = os.path.expanduser('~/.gvoice') 13 | 14 | if not os.path.exists(self.fname): 15 | try: 16 | with open(self.fname, 'w') as f: 17 | f.write(settings.DEFAULT_CONFIG) 18 | except IOError: 19 | return 20 | 21 | ConfigParser.__init__(self) 22 | 23 | try: 24 | self.read([self.fname]) 25 | except IOError: 26 | return 27 | 28 | def get(self, option, section='gvoice', **kwargs): 29 | try: 30 | return ConfigParser.get(self, section, option, **kwargs).strip() or None 31 | except NoOptionError: 32 | return 33 | 34 | def set(self, option, value, section='gvoice'): 35 | return ConfigParser.set(self, section, option, value) 36 | 37 | def phoneType(self): 38 | try: 39 | return int(self.get('phoneType')) 40 | except TypeError: 41 | return 42 | 43 | def save(self): 44 | with open(self.f, 'w') as f: 45 | f.write(f) 46 | 47 | phoneType = property(phoneType) 48 | forwardingNumber = property(lambda self: self.get('forwardingNumber')) 49 | email = property(lambda self: self.get('email', 'auth')) 50 | password = property(lambda self: self.get('password', 'auth')) 51 | smsKey = property(lambda self: self.get('smsKey', 'auth')) 52 | secret = property(lambda self: self.get('secret')) 53 | 54 | config = Config() 55 | -------------------------------------------------------------------------------- /pygooglevoice/googlevoice/settings.py: -------------------------------------------------------------------------------- 1 | DEFAULT_CONFIG = """ 2 | [auth] 3 | # Google Account email address (one associated w/ your Voice account) 4 | email= 5 | 6 | # Raw password used or login 7 | password= 8 | 9 | # Optional 2-step authentication key (as provided by Google) 10 | smsKey= 11 | 12 | [gvoice] 13 | # Number to place calls from (eg, your google voice number) 14 | forwardingNumber= 15 | 16 | # Default phoneType for your forwardingNumber as defined below 17 | # 1 - Home 18 | # 2 - Mobile 19 | # 3 - Work 20 | # 7 - Gizmo 21 | # 9 - Googletalk 22 | phoneType=2 23 | """ 24 | 25 | TYPES = { 26 | 0: 'missed', 27 | 1: 'received', 28 | 2: 'voicemail', 29 | 4: 'recorded', 30 | 7: 'placed', 31 | 10: 'sms.received', 32 | 11: 'sms.sent' 33 | } 34 | 35 | DEBUG = False 36 | 37 | LOGIN = 'https://accounts.google.com/ServiceLogin?continue=https://www.google.com/voice&rip=1&nojavascript=1&followup=https://www.google.com/voice&service=grandcentral<mpl=open&rip=1&flowName=GlifWebSignIn&flowEntry=Identifier' 38 | #LOGIN = 'https://accounts.google.com/ServiceLogin?continue=https://www.google.com/voice&rip=1&nojavascript=1&followup=https://www.google.com/voice&service=grandcentral<mpl=open&flowName=GlifWebSignIn&flowEntry=Identifier' 39 | 40 | LOGIN_POST = 'https://accounts.google.com/signin/challenge/sl/password?service=grandcentral&continue=https://www.google.com/voice/redirection/voice&followup=https://www.google.com/voice<mpl=open' 41 | 42 | USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36' 43 | 44 | SMSAUTH = 'https://accounts.google.com/SmsAuth' 45 | FEEDS = ('inbox', 'starred', 'all', 'history', 'spam', 'trash', 'voicemail', 'sms', 46 | 'recorded', 'placed', 'received', 'missed') 47 | 48 | BASE = 'https://www.google.com/voice/b/0/' 49 | LOGOUT = 'https://www.google.com/voice/account/signout' 50 | INBOX = BASE + '#inbox' 51 | HISTORY = BASE + '#history' 52 | CALL = BASE + 'call/connect/' 53 | CANCEL = BASE + 'call/cancel/' 54 | DEFAULT_FORWARD = BASE + 'settings/editDefaultForwarding/' 55 | FORWARD = BASE + 'settings/editForwarding/' 56 | SMS_FORWARD = BASE + 'settings/editForwardingSms/' 57 | VOICEMAILNOTIFY = BASE + 'settings/editVoicemailSms/' 58 | ADDNOTE = BASE + 'inbox/savenote/' 59 | DELETENOTE = BASE + 'inbox/deletenote/' 60 | DELETE = BASE + 'inbox/deleteMessages/' 61 | ARCHIVE = BASE + 'inbox/archiveMessages/' 62 | MARK = BASE + 'inbox/mark/' 63 | STAR = BASE + 'inbox/star/' 64 | BLOCK = BASE + 'inbox/block/' 65 | SMS = BASE + 'sms/send/' 66 | DOWNLOAD = BASE + 'media/send_voicemail/' 67 | BALANCE = BASE + 'settings/billingcredit/' 68 | 69 | XML_SEARCH = BASE + 'inbox/search/' 70 | XML_CONTACTS = BASE + 'contacts/' 71 | XML_RECENT = BASE + 'inbox/recent/' 72 | XML_MESSAGE = BASE + 'inbox/message/' 73 | XML_INBOX = XML_RECENT + 'inbox/' 74 | XML_STARRED = XML_RECENT + 'starred/' 75 | XML_ALL = XML_RECENT + 'all/' 76 | XML_HISTORY = XML_RECENT + 'history/' 77 | XML_SPAM = XML_RECENT + 'spam/' 78 | XML_TRASH = XML_RECENT + 'trash/' 79 | XML_VOICEMAIL = XML_RECENT + 'voicemail/' 80 | XML_SMS = XML_RECENT + 'sms/' 81 | XML_RECORDED = XML_RECENT + 'recorded/' 82 | XML_PLACED = XML_RECENT + 'placed/' 83 | XML_RECEIVED = XML_RECENT + 'received/' 84 | XML_MISSED = XML_RECENT + 'missed/' 85 | -------------------------------------------------------------------------------- /pygooglevoice/googlevoice/tests.py: -------------------------------------------------------------------------------- 1 | from googlevoice import Voice, util 2 | from os import path, remove 3 | from unittest import TestCase, main 4 | 5 | class VoiceTest(TestCase): 6 | voice = Voice() 7 | voice.login() 8 | outgoing = util.input('Outgoing number (blank to ignore call tests): ') 9 | forwarding = None 10 | if outgoing: 11 | forwarding = util.input('Forwarding number [optional]: ') or None 12 | 13 | if outgoing: 14 | def test_1call(self): 15 | self.voice.call(self.outgoing, self.forwarding) 16 | 17 | def test_sms(self): 18 | self.voice.send_sms(self.outgoing, 'i sms u') 19 | 20 | def test_2cancel(self): 21 | self.voice.cancel(self.outgoing, self.forwarding) 22 | 23 | def test_special(self): 24 | self.assert_(self.voice.special) 25 | 26 | def test_inbox(self): 27 | self.assert_(self.voice.inbox) 28 | 29 | def test_balance(self): 30 | self.assert_(self.voice.settings['credits']) 31 | 32 | def test_search(self): 33 | self.assert_(len(self.voice.search('joe'))) 34 | 35 | def test_disable_enable(self): 36 | self.voice.phones[0].disable() 37 | self.voice.phones[0].enable() 38 | 39 | def test_download(self): 40 | msg = list(self.voice.voicemail.messages)[0] 41 | fn = '%s.mp3' % msg.id 42 | if path.isfile(fn): remove(fn) 43 | self.voice.download(msg) 44 | self.assert_(path.isfile(fn)) 45 | 46 | def test_zlogout(self): 47 | self.voice.logout() 48 | self.assert_(self.voice.special is None) 49 | 50 | def test_config(self): 51 | from conf import config 52 | self.assert_(config.forwardingNumber) 53 | self.assert_(str(config.phoneType) in '1237') 54 | self.assertEqual(config.get('wtf'), None) 55 | 56 | if __name__ == '__main__': main() -------------------------------------------------------------------------------- /pygooglevoice/googlevoice/util.py: -------------------------------------------------------------------------------- 1 | import re 2 | from sys import stdout 3 | from xml.parsers.expat import ParserCreate 4 | from time import gmtime 5 | from datetime import datetime 6 | from pprint import pprint 7 | try: 8 | from urllib2 import build_opener,install_opener, \ 9 | HTTPCookieProcessor,Request,urlopen 10 | from urllib import urlencode,quote 11 | except ImportError: 12 | from urllib.request import build_opener,install_opener, \ 13 | HTTPCookieProcessor,Request,urlopen 14 | from urllib.parse import urlencode,quote 15 | try: 16 | from http.cookiejar import LWPCookieJar as CookieJar 17 | except ImportError: 18 | from cookielib import LWPCookieJar as CookieJar 19 | try: 20 | from json import loads 21 | except ImportError: 22 | from simplejson import loads 23 | try: 24 | input = raw_input 25 | except NameError: 26 | input = input 27 | 28 | sha1_re = re.compile(r'^[a-fA-F0-9]{40}$') 29 | 30 | def print_(*values, **kwargs): 31 | """ 32 | Implementation of Python3's print function 33 | 34 | Prints the values to a stream, or to sys.stdout by default. 35 | Optional keyword arguments: 36 | 37 | file: a file-like object (stream); defaults to the current sys.stdout. 38 | sep: string inserted between values, default a space. 39 | end: string appended after the last value, default a newline. 40 | """ 41 | fo = kwargs.pop('file', stdout) 42 | fo.write(kwargs.pop('sep', ' ').join(map(str, values))) 43 | fo.write(kwargs.pop('end', '\n')) 44 | fo.flush() 45 | 46 | def is_sha1(s): 47 | """ 48 | Returns ``True`` if the string is a SHA1 hash 49 | """ 50 | return bool(sha1_re.match(s)) 51 | 52 | def validate_response(response): 53 | """ 54 | Validates that the JSON response is A-OK 55 | """ 56 | try: 57 | assert 'ok' in response and response['ok'] 58 | except AssertionError: 59 | raise ValidationError('There was a problem with GV: %s' % response) 60 | 61 | def load_and_validate(response): 62 | """ 63 | Loads JSON data from http response then validates 64 | """ 65 | validate_response(loads(response.read())) 66 | 67 | class ValidationError(Exception): 68 | """ 69 | Bombs when response code back from Voice 500s 70 | """ 71 | 72 | class LoginError(Exception): 73 | """ 74 | Occurs when login credentials are incorrect 75 | """ 76 | 77 | class ParsingError(Exception): 78 | """ 79 | Happens when XML feed parsing fails 80 | """ 81 | 82 | class JSONError(Exception): 83 | """ 84 | Failed JSON deserialization 85 | """ 86 | 87 | class DownloadError(Exception): 88 | """ 89 | Cannot download message, probably not in voicemail/recorded 90 | """ 91 | 92 | class ForwardingError(Exception): 93 | """ 94 | Forwarding number given was incorrect 95 | """ 96 | 97 | 98 | class AttrDict(dict): 99 | def __getattr__(self, attr): 100 | if attr in self: 101 | return self[attr] 102 | 103 | class Phone(AttrDict): 104 | """ 105 | Wrapper for phone objects used for phone specific methods 106 | Attributes are: 107 | 108 | * id: int 109 | * phoneNumber: i18n phone number 110 | * formattedNumber: humanized phone number string 111 | * we: data dict 112 | * wd: data dict 113 | * verified: bool 114 | * name: strign label 115 | * smsEnabled: bool 116 | * scheduleSet: bool 117 | * policyBitmask: int 118 | * weekdayTimes: list 119 | * dEPRECATEDDisabled: bool 120 | * weekdayAllDay: bool 121 | * telephonyVerified 122 | * weekendTimes: list 123 | * active: bool 124 | * weekendAllDay: bool 125 | * enabledForOthers: bool 126 | * type: int (1 - Home, 2 - Mobile, 3 - Work, 4 - Gizmo) 127 | 128 | """ 129 | def __init__(self, voice, data): 130 | self.voice = voice 131 | super(Phone, self).__init__(data) 132 | 133 | def enable(self,): 134 | """ 135 | Enables this phone for usage 136 | """ 137 | return self.__call_forwarding() 138 | 139 | def disable(self): 140 | """ 141 | Disables this phone 142 | """ 143 | return self.__call_forwarding('0') 144 | 145 | def enableSMS(self): 146 | """ 147 | Enable sms forwarding to a forwarding phone 148 | """ 149 | return self.__sms_forwarding() 150 | 151 | def disableSMS(self): 152 | """ 153 | Disable sms forwarding to a forwarding phone 154 | """ 155 | return self.__sms_forwarding('0') 156 | 157 | def enableVoicemail(self,): 158 | """ 159 | Notify a forwarding number of new voicemails via text 160 | """ 161 | return self.__voice_notify() 162 | 163 | def disableVoicemail(self): 164 | """ 165 | Do not notify a forwarding number of new voicemails 166 | """ 167 | return self.__voice_notify('0') 168 | 169 | def __call_forwarding(self, enabled='1'): 170 | """ 171 | Enables or disables this phone 172 | """ 173 | self.voice.__validate_special_page('default_forward', {'enabled':enabled, 'phoneId': self.id}) 174 | 175 | def __sms_forwarding(self, enabled='1'): 176 | """ 177 | Endable or Disable sms forwarding to a forwarding phone 178 | """ 179 | self.voice.__validate_special_page('sms_forward', {'enabled':enabled, 'phoneId': self.id}) 180 | 181 | def __voice_notify(self, enabled='1'): 182 | """ 183 | Endable or Disable notify a forwarding number of new voicemails 184 | """ 185 | self.voice.__validate_special_page('voicemailNotify', {'enabled':enabled, 'phoneId': self.id}) 186 | 187 | def __str__(self): 188 | return self.phoneNumber 189 | 190 | def __repr__(self): 191 | return '' % self.phoneNumber 192 | 193 | class Message(AttrDict): 194 | """ 195 | Wrapper for all call/sms message instances stored in Google Voice 196 | Attributes are: 197 | 198 | * id: SHA1 identifier 199 | * isTrash: bool 200 | * displayStartDateTime: datetime 201 | * star: bool 202 | * isSpam: bool 203 | * startTime: gmtime 204 | * labels: list 205 | * displayStartTime: time 206 | * children: str 207 | * note: str 208 | * isRead: bool 209 | * displayNumber: str 210 | * relativeStartTime: str 211 | * phoneNumber: str 212 | * type: int 213 | 214 | """ 215 | def __init__(self, folder, id, data): 216 | #assert is_sha1(id), 'Message id not a SHA1 hash' 217 | self.folder = folder 218 | self.id = id 219 | super(AttrDict, self).__init__(data) 220 | self['startTime'] = gmtime(int(self['startTime'])/1000) 221 | self['displayStartDateTime'] = datetime.strptime( 222 | self['displayStartDateTime'], '%m/%d/%y %I:%M %p') 223 | self['displayStartTime'] = self['displayStartDateTime'].time() 224 | 225 | def delete(self, trash=1): 226 | """ 227 | Moves this message to the Trash. Use ``message.delete(0)`` to move it out of the Trash. 228 | """ 229 | self.folder.voice.__messages_post('delete', self.id, trash=trash) 230 | 231 | def star(self, star=1): 232 | """ 233 | Star this message. Use ``message.star(0)`` to unstar it. 234 | """ 235 | self.folder.voice.__messages_post('star', self.id, star=star) 236 | 237 | def mark(self, read=1): 238 | """ 239 | Mark this message as read. Use ``message.mark(0)`` to mark it as unread. 240 | """ 241 | self.folder.voice.__messages_post('mark', self.id, read=read) 242 | 243 | def download(self, adir=None): 244 | """ 245 | Download the message MP3 (if any). 246 | Saves files to ``adir`` (defaults to current directory). 247 | Message hashes can be found in ``self.voicemail().messages`` for example. 248 | Returns location of saved file. 249 | """ 250 | return self.folder.voice.download(self, adir) 251 | 252 | def __str__(self): 253 | return self.id 254 | 255 | def __repr__(self): 256 | return '' % (self.id, self.phoneNumber) 257 | 258 | class Folder(AttrDict): 259 | """ 260 | Folder wrapper for feeds from Google Voice 261 | Attributes are: 262 | 263 | * totalSize: int (aka ``__len__``) 264 | * unreadCounts: dict 265 | * resultsPerPage: int 266 | * messages: list of Message instances 267 | """ 268 | def __init__(self, voice, name, data): 269 | self.voice = voice 270 | self.name = name 271 | super(AttrDict, self).__init__(data) 272 | 273 | def messages(self): 274 | """ 275 | Returns a list of all messages in this folder 276 | """ 277 | return [Message(self, *i) for i in self['messages'].items()] 278 | messages = property(messages) 279 | 280 | def __len__(self): 281 | return self['totalSize'] 282 | 283 | def __repr__(self): 284 | return '' % (self.name, len(self)) 285 | 286 | class XMLParser(object): 287 | """ 288 | XML Parser helper that can dig json and html out of the feeds. 289 | The parser takes a ``Voice`` instance, page name, and function to grab data from. 290 | Calling the parser calls the data function once, sets up the ``json`` and ``html`` 291 | attributes and returns a ``Folder`` instance for the given page:: 292 | 293 | >>> o = XMLParser(voice, 'voicemail', lambda: 'some xml payload') 294 | >>> o() 295 | ... 296 | >>> o.json 297 | ... 'some json payload' 298 | >>> o.data 299 | ... 'loaded json payload' 300 | >>> o.html 301 | ... 'some html payload' 302 | 303 | """ 304 | attr = None 305 | 306 | def start_element(self, name, attrs): 307 | if name in ('json','html'): 308 | self.attr = name 309 | def end_element(self, name): self.attr = None 310 | def char_data(self, data): 311 | if self.attr and data: 312 | setattr(self, self.attr, getattr(self, self.attr) + data) 313 | 314 | def __init__(self, voice, name, datafunc): 315 | self.json, self.html = '','' 316 | self.datafunc = datafunc 317 | self.voice = voice 318 | self.name = name 319 | 320 | def __call__(self): 321 | self.json, self.html = '','' 322 | parser = ParserCreate() 323 | parser.StartElementHandler = self.start_element 324 | parser.EndElementHandler = self.end_element 325 | parser.CharacterDataHandler = self.char_data 326 | try: 327 | data = self.datafunc() 328 | parser.Parse(data, 1) 329 | except: 330 | raise ParsingError 331 | return self.folder 332 | 333 | def folder(self): 334 | """ 335 | Returns associated ``Folder`` instance for given page (``self.name``) 336 | """ 337 | return Folder(self.voice, self.name, self.data) 338 | folder = property(folder) 339 | 340 | def data(self): 341 | """ 342 | Returns the parsed json information after calling the XMLParser 343 | """ 344 | try: 345 | return loads(self.json) 346 | except: 347 | raise JSONError 348 | data = property(data) 349 | 350 | -------------------------------------------------------------------------------- /pygooglevoice/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | 4 | README = """Python Google Voice 5 | ==================== 6 | 7 | Joe McCall & Justin Quick 8 | 9 | Exposing the Google Voice "API" to the Python language 10 | ------------------------------------------------------- 11 | 12 | Google Voice for Python Allows you to place calls, send sms, download voicemail, and check the various folders of your Google Voice Accounts. 13 | You can use the Python API or command line script to schedule calls, check for new recieved calls/sms, or even sync your recorded voicemails/calls. 14 | Works for Python 2 and Python 3 15 | 16 | Full documentation is available up at http://sphinxdoc.github.com/pygooglevoice/ 17 | """ 18 | 19 | setup( 20 | name = "pygooglevoice", 21 | version = '0.5', 22 | url = 'http://code.google.com/p/pygooglevoice', 23 | author = 'Justin Quick and Joe McCall', 24 | author_email='justquick@gmail.com, joe@mcc4ll.us', 25 | description = 'Python 2/3 Interface for Google Voice', 26 | long_description = README, 27 | packages = ['googlevoice'], 28 | scripts = ['bin/gvoice','bin/asterisk-gvoice-setup', 'bin/gvi'] 29 | ) -------------------------------------------------------------------------------- /screenshoot1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/screenshoot1.jpg -------------------------------------------------------------------------------- /screenshoot2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheTechsTech/minigooglevoice/4995e15f6265896c78c2d960765416d1460a0755/screenshoot2.jpg -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | cd pygooglevoice 2 | python setup.py install 3 | cd ../BeautifulSoup-3.2.1 4 | python setup.py install 5 | pip install --upgrade BeautifulSoup 6 | cd .. 7 | chmod +x gvactions.py 8 | chmod +x gvaddnote.py 9 | chmod +x gvcall.py 10 | chmod +x gvcallcancel.py 11 | chmod +x gvdetails.py 12 | chmod +x gvhistory.py 13 | chmod +x gvmessages.py 14 | chmod +x gvrecorded-mp3.py 15 | chmod +x gvsendsms.py 16 | chmod +x gvsettingcheck.py 17 | chmod +x gvvoicemail-mp3.py 18 | exit 19 | --------------------------------------------------------------------------------