├── database ├── migrations │ ├── .gitkeep │ ├── 2021_10_13_201913_add_email_id_to_users_table.php │ ├── 2021_06_28_202800_create_systems_table.php │ ├── 2022_03_03_164000_add_allowhmp_to_systems_table .php │ ├── 2022_01_25_180344_create_caller_table.php │ ├── 2021_01_09_152605_create_users_table.php │ └── 2021_01_18_180344_create_messages_table.php ├── factories │ └── UserFactory.php └── seeders │ └── DatabaseSeeder.php ├── resources └── views │ ├── .gitkeep │ └── mail.blade.php ├── app ├── Console │ ├── Commands │ │ └── .gitkeep │ └── Kernel.php ├── Events │ ├── Event.php │ └── ExampleEvent.php ├── Http │ ├── Controllers │ │ ├── Controller.php │ │ ├── GeoLocationController.php │ │ ├── CallerController.php │ │ ├── HelpController.php │ │ ├── FileController.php │ │ ├── UserController.php │ │ ├── SystemController.php │ │ ├── MessageController.php │ │ └── RadioController.php │ └── Middleware │ │ ├── BeforeMiddleware.php │ │ ├── AfterMiddleware.php │ │ ├── OldMiddleware.php │ │ ├── Authenticate.php │ │ └── CorsMiddleware.php ├── System.php ├── Providers │ ├── AppServiceProvider.php │ ├── EventServiceProvider.php │ └── AuthServiceProvider.php ├── Jobs │ ├── ExampleJob.php │ └── Job.php ├── Listeners │ └── ExampleListener.php ├── Caller.php ├── Message.php ├── Models │ └── User.php ├── User.php ├── Exceptions │ └── Handler.php └── Functions.php ├── storage ├── app │ └── .gitignore ├── logs │ └── .gitignore └── framework │ ├── views │ └── .gitignore │ └── cache │ ├── data │ └── .gitignore │ └── .gitignore ├── .styleci.yml ├── scripts ├── clean_files.sh ├── disable_monitor.sh ├── enable_monitor.sh ├── inboxunpacker.sh ├── monitor.sh ├── alias.sh └── compress_image.sh ├── .gitignore ├── .ac-php-conf.json ├── .editorconfig ├── public ├── .htaccess └── index.php ├── tests ├── TestCase.php └── ExampleTest.php ├── phpunit.xml ├── .github └── workflows │ └── php.yml ├── artisan ├── .env.example ├── composer.json ├── README.md ├── config ├── filesystem.php └── mail.php ├── bootstrap └── app.php ├── routes └── web.php └── LICENSE /database/migrations/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/Console/Commands/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | php: 2 | preset: laravel 3 | disabled: 4 | - unused_use 5 | js: true 6 | css: true 7 | -------------------------------------------------------------------------------- /scripts/clean_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo rm -rf /var/www/html/uploads/* 4 | sudo rm -rf /var/www/html/arquivos/* 5 | -------------------------------------------------------------------------------- /scripts/disable_monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export LD_LIBRARY_PATH=/opt/vc/lib/ 4 | /opt/vc/bin/vcgencmd display_power 0 5 | -------------------------------------------------------------------------------- /scripts/enable_monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export LD_LIBRARY_PATH=/opt/vc/lib/ 4 | /opt/vc/bin/vcgencmd display_power 1 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | Homestead.json 4 | Homestead.yaml 5 | .env 6 | .phpunit.result.cache 7 | composer.lock 8 | database/database.sqlite 9 | -------------------------------------------------------------------------------- /scripts/inboxunpacker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for f in *; do 4 | echo "File -> $f" 5 | curl http://localhost/inbox/unpack $f 6 | # rm $f 7 | done 8 | 9 | -------------------------------------------------------------------------------- /scripts/monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | inotifywait -q --format '%f' -m -r -e close_write,moved_to . | xargs -I{} -r sh -c 'curl http://localhost/api/unpack/$(basename {}) -k' 3 | -------------------------------------------------------------------------------- /app/Events/Event.php: -------------------------------------------------------------------------------- 1 |

Hi

2 |

this is a message from hermes system that arrives in your territory

3 | 4 | 5 |

Subject: {{ $name }}

6 |
7 |

Message: {{ $text }}

8 | 9 |

sent: {{ $sent_at}}

10 | 11 |

origin station: {{ $orig }}

12 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteCond %{REQUEST_FILENAME} !-f 4 | RewriteCond %{REQUEST_FILENAME} !-d 5 | RewriteRule ^ index.php [QSA,L] 6 | php_value upload_max_filesize 256M 7 | php_value post_max_size 256M 8 | php_value max_execution_time 600 9 | php_value max_input_time 600 10 | client_max_body_size 256M 11 | 12 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | get('/'); 16 | 17 | $this->assertEquals( 18 | $this->app->version(), $this->response->getContent() 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 16 | \App\Listeners\ExampleListener::class, 17 | ], 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Middleware/OldMiddleware.php: -------------------------------------------------------------------------------- 1 | input('age') <= 200) { 19 | return redirect('home'); 20 | } 21 | 22 | return $next($request); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/Listeners/ExampleListener.php: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | $this->faker->name, 26 | 'email' => $this->faker->unique()->safeEmail, 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Caller.php: -------------------------------------------------------------------------------- 1 | 'array', 21 | ]; 22 | 23 | /** 24 | * The attributes excluded from the model's JSON form. 25 | * 26 | * @var array 27 | */ 28 | protected $hidden = [ 29 | 'updated_at', 'created_at' 30 | ]; 31 | 32 | protected $table = 'caller'; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /app/Message.php: -------------------------------------------------------------------------------- 1 | 'array', 21 | ]; 22 | 23 | /** 24 | * The attributes excluded from the model's JSON form. 25 | * 26 | * @var array 27 | */ 28 | protected $hidden = [ 29 | 'updated_at', 'created_at' 30 | ]; 31 | } -------------------------------------------------------------------------------- /app/Jobs/Job.php: -------------------------------------------------------------------------------- 1 | string('emailid')->nullable(true); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | * 25 | * @return void 26 | */ 27 | public function down() 28 | { 29 | Schema::table('users', function (Blueprint $table) { 30 | // 31 | }); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /database/migrations/2021_06_28_202800_create_systems_table.php: -------------------------------------------------------------------------------- 1 | string('host'); 18 | $table->string('allowfile')->default('users'); 19 | $table->timestamps(); 20 | 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('systems'); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /database/migrations/2022_03_03_164000_add_allowhmp_to_systems_table .php: -------------------------------------------------------------------------------- 1 | string('allowhmp')->default('admin'); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | * 25 | * @return void 26 | */ 27 | public function down() 28 | { 29 | Schema::table('systems', function (Blueprint $table) { 30 | // 31 | }); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /scripts/compress_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # uso: 3 | # compress_image.sh arquivo_para_comprimir.jpg 4 | MAX_SIZE=${MAX_SIZE:=51200} # 50kB file size limit 5 | QUALITY=75 # initial start quality to try... 6 | 7 | TEMPFILE=/tmp/temp-$$.jpg 8 | 9 | 10 | if [ $# -lt 1 ]; then 11 | echo "Usage: $0 image_filename.jpg" 12 | echo "Usage: $0 image_filename.{png,gif,...} output.jpg" 13 | exit 1 14 | fi 15 | 16 | # while [[ stat -c ${1} ]] 17 | # echo $(stat -c%s "${1}") 18 | cp -f "${1}" ${TEMPFILE} 19 | 20 | while [ "$(stat -c%s "${TEMPFILE}")" -gt "$MAX_SIZE" ] && [ "$QUALITY" -gt "5" ]; do 21 | # echo $(stat -c%s "${TEMPFILE}") 22 | convert -resize "840x840>" "${1}" pnm:- | /opt/mozjpeg/bin/cjpeg -quality ${QUALITY} > ${TEMPFILE} 23 | QUALITY=$((QUALITY-10)) 24 | # echo ${QUALITY} 25 | done; 26 | 27 | if [ $# -eq 1 ]; then 28 | mv ${TEMPFILE} "${1}" 29 | fi 30 | 31 | if [ $# -eq 2 ]; then 32 | mv ${TEMPFILE} "${2}" 33 | fi 34 | -------------------------------------------------------------------------------- /app/Models/User.php: -------------------------------------------------------------------------------- 1 | run(); 29 | -------------------------------------------------------------------------------- /app/User.php: -------------------------------------------------------------------------------- 1 | json(['message' => 'No GPS found for calibration: ' . $output], 500); 22 | 23 | if(!$output || $output == 'ERROR') 24 | return response()->json(['message' => 'Fail on start GPS calibration: ' . $output], 500); 25 | 26 | return response()->json(['message' => 'GPS Calibration successful'], 200); 27 | 28 | } catch (\Throwable $th) { 29 | return response()->json(['message' => 'Internal Server Error:' . $th], 500); 30 | } 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /database/migrations/2022_01_25_180344_create_caller_table.php: -------------------------------------------------------------------------------- 1 | increments('id')->unique(); 18 | $table->string('title')->nullable(true); 19 | $table->json('stations')->nullable(true); 20 | $table->time('starttime')->default(true); 21 | $table->time('stoptime')->default(false); 22 | $table->boolean('enable')->default(false); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('caller'); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 26 | } 27 | 28 | /** 29 | * Handle an incoming request. 30 | * 31 | * @param \Illuminate\Http\Request $request 32 | * @param \Closure $next 33 | * @param string|null $guard 34 | * @return mixed 35 | */ 36 | public function handle($request, Closure $next, $guard = null) 37 | { 38 | if ($this->auth->guard($guard)->guest()) { 39 | return response('Unauthorized.', 401); 40 | } 41 | 42 | return $next($request); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | app['auth']->viaRequest('api', function ($request) { 34 | if ($request->input('api_token')) { 35 | return User::where('api_token', $request->input('api_token'))->first(); 36 | } 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/migrations/2021_01_09_152605_create_users_table.php: -------------------------------------------------------------------------------- 1 | string('email')->unique(); 18 | $table->string('name'); 19 | $table->string('password'); 20 | $table->string('phone')->nullable(true); 21 | $table->string('site')->nullable(true); 22 | $table->string('location')->nullable(true); 23 | $table->string('recoverphrase')->nullable(true); 24 | $table->string('recoveranswer')->nullable(true); 25 | $table->boolean('admin')->nullable(true);; 26 | $table->timestamps(); 27 | }); 28 | } 29 | 30 | /** 31 | * Reverse the migrations. 32 | * 33 | * @return void 34 | */ 35 | public function down() 36 | { 37 | Schema::dropIfExists('users'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make( 32 | 'Illuminate\Contracts\Console\Kernel' 33 | ); 34 | 35 | exit($kernel->handle(new ArgvInput, new ConsoleOutput)); 36 | -------------------------------------------------------------------------------- /app/Http/Middleware/CorsMiddleware.php: -------------------------------------------------------------------------------- 1 | '*', 20 | 'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE', 21 | 'Access-Control-Allow-Credentials' => 'true', 22 | 'Access-Control-Max-Age' => '86400', 23 | 'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With' 24 | ]; 25 | 26 | if ($request->isMethod('OPTIONS')) 27 | { 28 | return response()->json('{"method":"OPTIONS"}', 200, $headers); 29 | } 30 | 31 | $response = $next($request); 32 | foreach($headers as $key => $value) 33 | { 34 | $response->header($key, $value); 35 | } 36 | return $response; 37 | } 38 | } -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Lumen 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | APP_TIMEZONE=UTC 7 | MAX_FILE_SIZE=104857600 8 | 9 | LOG_CHANNEL=stack 10 | LOG_SLACK_WEBHOOK_URL= 11 | 12 | DB_CONNECTION=sqlite 13 | 14 | #DB_HOST=127.0.0.1 15 | #DB_PORT=3306 16 | #DB_DATABASE=hermes 17 | #DB_USERNAME=hermes 18 | #DB_PASSWORD=secret 19 | 20 | CACHE_DRIVER=file 21 | QUEUE_CONNECTION=sync 22 | 23 | HERMES_GATEWAY=true // set if station is a HERMES gateway 24 | HERMES_NETWORK=hermes.radio 25 | HERMES_NAME=trambolho 26 | HERMES_DOMAIN=hermes.radio 27 | HERMES_PATH=/hermes/ 28 | HERMES_INBOX=inbox/ 29 | HERMES_OUTBOX=outbox/ 30 | HERMES_TOOL=/usr/bin/ubitx_client 31 | HERMES_ROUTE = gw!hermes 32 | HERMES_MAX_FILE=20480 33 | HERMES_MAX_SPOOL=81920 34 | #HERMES_GATEWAY=true 35 | 36 | HERMES_EMAILAPI_USER = apiadm 37 | HERMES_EMAILAPI_PASS = hermescaduceu 38 | HERMES_EMAILAPI_LOC = https://localhost:8080/remote/index.php 39 | HERMES_EMAILAPI_URI = https://localhost:8080/remote 40 | 41 | HERMES_EMAILAPI_FORWARDING_ID=1 42 | 43 | HERMES_FWD_EMAIL=todos@ga.hermes.radio 44 | 45 | MAIL_DRIVER=smtp 46 | MAIL_HOST=localhost 47 | MAIL_PORT=25 # 25,465,587 48 | MAIL_USERNAME=root@ga.hermes.radio 49 | MAIL_PASSWORD=caduceu 50 | MAIL_ENCRYPTION=null 51 | MAIL_FROM_ADDRESS=root@ga.hermes.radio 52 | MAIL_FROM_NAME="Sistema Hermes" 53 | -------------------------------------------------------------------------------- /database/migrations/2021_01_18_180344_create_messages_table.php: -------------------------------------------------------------------------------- 1 | increments('id')->unique(); 18 | $table->string('name'); 19 | $table->string('orig'); 20 | $table->json('dest')->nullable(false); 21 | $table->string('file')->nullable(true); 22 | $table->string('fileid')->nullable(true); 23 | $table->string('mimetype')->nullable(true); 24 | $table->text('text'); 25 | $table->string('sent_at')->nullable(true); 26 | $table->boolean('draft')->default(true); 27 | $table->boolean('inbox')->default(false); 28 | $table->boolean('secure')->default(false); 29 | $table->timestamps(); 30 | }); 31 | } 32 | 33 | /** 34 | * Reverse the migrations. 35 | * 36 | * @return void 37 | */ 38 | public function down() 39 | { 40 | Schema::dropIfExists('messages'); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/lumen", 3 | "description": "The Laravel Lumen Framework.", 4 | "keywords": ["framework", "laravel", "lumen"], 5 | "license": "MIT", 6 | "type": "project", 7 | "require": { 8 | "php": "^7.3|^8.0", 9 | "laravel/lumen-framework": "^8.0", 10 | "league/flysystem": "^1.1.4", 11 | "illuminate/database": "8.49.0", 12 | "illuminate/mail": "^8.83" 13 | }, 14 | 15 | "require-dev": { 16 | "fakerphp/faker": "^1.9.1", 17 | "league/flysystem": "^1.1.4", 18 | "mockery/mockery": "^1.3.1", 19 | "phpunit/phpunit": "^9.3" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "App\\": "app/", 24 | "Database\\Factories\\": "database/factories/", 25 | "Database\\Seeders\\": "database/seeders/" 26 | }, 27 | "files": ["app/Functions.php"] 28 | 29 | }, 30 | "autoload-dev": { 31 | "classmap": [ 32 | "tests/" 33 | ] 34 | }, 35 | "config": { 36 | "preferred-install": "dist", 37 | "sort-packages": true, 38 | "optimize-autoloader": true 39 | }, 40 | "minimum-stability": "dev", 41 | "prefer-stable": true, 42 | "scripts": { 43 | "post-root-package-install": [ 44 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 45 | ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hermes Project 2 | [Hermes](https://www.rhizomatica.org/hermes/) - High-frequency Emergency and Rural Multimedia Exchange System. 3 | 4 | 5 | ## Hermes station api 6 | This is a REST api for use on Hermes stations to exchange messages between then, 7 | it uses [Lumen PHP Framework](https://lumen.laravel.com/) and composer to manage its own dependencies. 8 | 9 | ## Server Requirements: 10 | - web server 11 | - PHP >= 7.3 12 | - OpenSSL PHP Extension 13 | - PDO PHP Extension 14 | - Mbstring PHP Extension 15 | - SQLite DataBase 16 | 17 | ## to configure 18 | - Setup your settings creating a .env file from .env.example 19 | 20 | - Setup public folders inbox / outbox to uucp public 21 | 22 | - set enebled in `php.ini` 23 | `extension=pdo_sqlite` 24 | `extension=mbstring` 25 | `extension=odbc` 26 | `extension=openssl` 27 | 28 | - Run: 29 | composer install 30 | 31 | - create `database.sqlite` file in database folder 32 | 33 | - To start a fresh database: 34 | php artisan migrate:refresh --seed 35 | 36 | ## Running on port 8000: 37 | ❯ php -S localhost:8000 -t public 38 | 39 | ## Hermes Message Pack 40 | is a tar gziped file named .hmp 41 | 42 | ## storage local file structure paths (storage/app/) 43 | 44 | uploads (Files of outgoing messages) 45 | downloads (Files generated from the inbox received messages) 46 | inbox (incoming hermes message packs) 47 | outbox (hermes message pack for deliver) 48 | tmp (tmp files) 49 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | insert([ 20 | 'email' => 'root', 21 | 'name' => 'admin', 22 | 'password' => hash('sha256', 'caduceu'), 23 | 'location' => 'local', 24 | 'admin' => true 25 | ]); 26 | 27 | DB::table('systems')->insert([ 28 | 'host' => 'stationx.hermes.radio', 29 | 'allowfile' => 'users' 30 | ]); 31 | 32 | DB::table('messages')->insert([ 33 | 'name' => 'send test message ', 34 | 'orig' => 'local', 35 | 'dest' => '["local"]', 36 | 'text' => 'lorem ipsum', 37 | 'draft' => false 38 | ]); 39 | 40 | db::table('messages')->insert([ 41 | 'name' => 'bienvenido ', 42 | 'orig' => 'local', 43 | 'dest' => '["local"]', 44 | 'text' => 'Bienvenido ao sistema Hermes', 45 | 'draft' => false, 46 | 'inbox' => true 47 | ]); 48 | 49 | DB::table('messages')->insert([ 50 | 'name' => 'stuck test message '.Str::random(10), 51 | 'orig' => 'local', 52 | 'dest' => '["local"]', 53 | 'text' => 'lorem ipsum', 54 | 'draft' => true 55 | ]); 56 | for($a=1; $a<=2; $a++){ 57 | DB::table('messages')->insert([ 58 | 'name' => 'send message seeded'.Str::random(0), 59 | 'orig' => 'local', 60 | 'dest' => '["local"]', 61 | 'text' => 'lorem ipsum', 62 | 'draft' => false 63 | ]); 64 | } 65 | 66 | DB::table('caller')->insert([ 67 | 'title' => 'default', 68 | 'stations' => '["local"]', 69 | 'starttime' => '00:00:00', 70 | 'stoptime' => '24:00:00', 71 | 'enable' => false 72 | ]); 73 | 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /config/filesystem.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DRIVER', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Filesystem Disks 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure as many filesystem "disks" as you wish, and you 24 | | may even configure multiple disks of the same driver. Defaults have 25 | | been setup for each driver as an example of the required options. 26 | | 27 | | Supported Drivers: "local", "ftp", "sftp", "s3" 28 | | 29 | */ 30 | 31 | 'disks' => [ 32 | 33 | 'local' => [ 34 | 'driver' => 'local', 35 | 'root' => storage_path('app'), 36 | 'url' => env('APP_URL').'/storage', 37 | 'visibility' => 'public' 38 | ], 39 | 'public' => [ 40 | 'driver' => 'local', 41 | //'root' => storage_path('app/public'), 42 | 'root' => storage_path('app/public'), 43 | 'url' => env('APP_URL').'/public/', 44 | 'visibility' => 'public' 45 | ], 46 | 47 | 's3' => [ 48 | 'driver' => 's3', 49 | 'key' => env('AWS_ACCESS_KEY_ID'), 50 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 51 | 'region' => env('AWS_DEFAULT_REGION'), 52 | 'bucket' => env('AWS_BUCKET'), 53 | 'url' => env('AWS_URL'), 54 | 'endpoint' => env('AWS_ENDPOINT') 55 | ], 56 | 57 | ], 58 | 59 | /* 60 | |-------------------------------------------------------------------------- 61 | | Symbolic Links 62 | |-------------------------------------------------------------------------- 63 | | 64 | | Here you may configure the symbolic links that will be created when the 65 | | `storage:link` Artisan command is executed. The array keys should be 66 | | the locations of the links and the values should be their targets. 67 | | 68 | */ 69 | 70 | 'links' => [ 71 | public_path('storage') => storage_path('app/public'), 72 | ] 73 | 74 | ]; 75 | -------------------------------------------------------------------------------- /app/Functions.php: -------------------------------------------------------------------------------- 1 | json(Caller::all()); 21 | } 22 | 23 | /** 24 | * show a schedule 25 | * parameter: schedule id 26 | * 27 | * @return Json 28 | */ 29 | public function showSched($id) 30 | { 31 | return response()->json(Caller::find($id)); 32 | } 33 | 34 | /** 35 | * createSched- createSched 36 | * parameter: http request 37 | * 38 | * @return Json 39 | */ 40 | public function createSched(Request $request) 41 | { 42 | $this->validate($request, [ 43 | 'title' => 'required|unique:caller', 44 | 'stations' => 'required|array', 45 | 'starttime' => 'required|date_format:H:i:s|before:stoptime', 46 | 'stoptime' => 'required|date_format:H:i:s|after:starttime', 47 | 'enable' => 'required|boolean' 48 | ]); 49 | 50 | if ( ! $request->title || ! $request->starttime || ! $request->stoptime || ! $request->enable ){ 51 | return response()->json(['message' => 'caller: require all fields ' ], 500); 52 | } 53 | 54 | $schedule = Caller::create($request->all()); 55 | if (! $schedule ){ 56 | return response()->json(['message' => 'caller: cant\'t create a schedule: ' ], 500); 57 | } 58 | else { 59 | //Log::info('creating schedule ' . $schedule); 60 | return response()->json( $request->all() , 200); 61 | } 62 | 63 | } 64 | 65 | /** 66 | * updateScheduler 67 | * parameter: id and http request 68 | * 69 | * @return Json 70 | */ 71 | public function updateSched($id, Request $request) 72 | { 73 | $this->validate($request, [ 74 | 'title' => 'required', 75 | 'stations' => 'required|array', 76 | 'starttime' => 'required|date_format:H:i:s|before:stoptime', 77 | 'stoptime' => 'required|date_format:H:i:s|after:starttime', 78 | 'enable' => 'required|boolean' 79 | ]); 80 | if($schedule = Caller::findOrFail($id)){ 81 | $schedule->update($request->all()); 82 | Log::info('update schedule' . $id); 83 | return response()->json($request, 200); 84 | } 85 | else{ 86 | Log::warning('schedule cant find to update' . $id); 87 | return response()->json(['message' => 'cant find schedule' . $id], 404); 88 | } 89 | } 90 | 91 | /** 92 | * deleteSched - deleteScheduler 93 | * parameter: scheduler id 94 | * @return Json 95 | */ 96 | public function deleteSched($id) 97 | { 98 | $schedule = Caller::findOrFail($id); 99 | Caller::findOrFail($id)->delete(); 100 | Log::info('delete schedule ' . $id); 101 | return response()->json(['message' => 'Delete sucessfully schedule: ' . $id], 200); 102 | } 103 | 104 | /** 105 | * set enable 106 | * parameter: schedule id 107 | * 108 | * @return Json 109 | */ 110 | public function setEnable($id) 111 | { 112 | // return response()->json(['unhide' . $id . 'Sucessfully'], 200); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/Http/Controllers/HelpController.php: -------------------------------------------------------------------------------- 1 | 'V1.0 - default page and help', 16 | '---------------------------' => '----------------------------------------', 17 | '--------SITE---------------' => 'https://hermes.radio', 18 | '---------------------------' => '----------------------------------------', 19 | '--------SYS----------------' => '----------------------------------------', 20 | 'sys/help GET' => 'this help', 21 | 'sys/status GET' => 'system status', 22 | 'sys/getnodename GET' => 'node name ( radio CALLSIGN)', 23 | 'sys/stations GET' => 'show available stations', 24 | 'sys/maillog GET' => 'get mail log', 25 | 'sys/restart GET' => 'restart', 26 | 'sys/reboot GET' => 'reboot', 27 | 'sys/sensors GET' => 'sensors', 28 | 'sys/shutdown GET' => 'cli: shutdown', 29 | '--------SYS-UUCP-----------' => '----------------------------------------', 30 | 'sys/uuk/id POST' => 'UUCP kill ID', 31 | 'sys/uuka POST' => 'UUCP killall jobs', 32 | 'sys/uuls GET' => 'UUCP list jobs', 33 | 'sys/uulog GET' => 'UUCP log', 34 | 'sys/uudebug GET' => 'UUCP debug log', 35 | '--------USERS--------------' => '----------------------------------------', 36 | 'user POST' => 'Create user and email', 37 | 'user/{id} GET' => 'Show a user', 38 | 'user/{id} PUT' => 'Update User', 39 | 'user/{id} DELETE' => 'Delete a user', 40 | 'users GET' => 'Show all users', 41 | '--------MESSAGES-----------' => '----------------------------------------', 42 | 'message POST' => 'Create message', 43 | 'message/{id} GET' => 'Show a message', 44 | 'message/{id} PUT' => 'Update a message', 45 | 'message/{id} DELETE' => 'Delete a message', 46 | 'messages GET' => 'Show all messages', 47 | '--------INBOX--------------' => '----------------------------------------', 48 | 'inbox/{id} GET' => 'Show a message', 49 | 'inbox GET' => 'Show all messages', 50 | 'unpack/{id} PUT' => 'unpack message', 51 | '--------FILES--------------' => '----------------------------------------', 52 | 'file POST' => 'upload, compress and crypt a file', 53 | 'file/{id} GET' => 'download, decompress and decrypt a file', 54 | '--------RADIO--------------' => '----------------------------------------', 55 | 'radio/status GET' => 'get radio status', 56 | 'radio/mode GET' => 'get radio mode', 57 | 'radio/mode/{mode} POST' => 'set radio mode', 58 | 'radio/freq GET' => 'get radio freq', 59 | 'radio/freq/{freq in hz} POST' => 'set radio freq', 60 | 'radio/bfo GET' => 'get Radio Freq', 61 | 'radio/bfo/{freq in hz} POST' => 'set radio bfo', 62 | 'radio/fwd GET' => 'get radio fwd', 63 | 'radio/fwd/{freq in hz} POST' => 'set radio fwd', 64 | 'radio/led GET' => 'get radio LED Status', 65 | 'radio/led/{status} POST' => 'set radio LED status', 66 | 'radio/ref GET' => 'get radio ref', 67 | 'radio/txrx GET' => 'get radioTxrx', 68 | 'radio/mastercal GET' => 'get radio MasterCal', 69 | 'radio/mastercal POST' => 'get radio MasterCal', 70 | 'radio/protection GET' => 'get radio MasterCal', 71 | 'radio/connection GET' => 'get radio ConnectionStatus', 72 | 'radio/connection/{status} POST' => 'get radio ConnectionStatus' 73 | ]; 74 | return $manual; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_MAILER', 'smtp'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Mailer Configurations 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure all of the mailers used by your application plus 24 | | their respective settings. Several examples have been configured for 25 | | you and you are free to add your own as your application requires. 26 | | 27 | | Laravel supports a variety of mail "transport" drivers to be used while 28 | | sending an e-mail. You will specify which one you are using for your 29 | | mailers below. You are free to add additional mailers as required. 30 | | 31 | | Supported: "smtp", "sendmail", "mailgun", "ses", 32 | | "postmark", "log", "array", "failover" 33 | | 34 | */ 35 | 36 | 'mailers' => [ 37 | 'smtp' => [ 38 | 'transport' => 'smtp', 39 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), 40 | 'port' => env('MAIL_PORT', 587), 41 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 42 | 'username' => env('MAIL_USERNAME'), 43 | 'password' => env('MAIL_PASSWORD'), 44 | 'timeout' => null, 45 | ], 46 | 47 | 'ses' => [ 48 | 'transport' => 'ses', 49 | ], 50 | 51 | 'mailgun' => [ 52 | 'transport' => 'mailgun', 53 | ], 54 | 55 | 'postmark' => [ 56 | 'transport' => 'postmark', 57 | ], 58 | 59 | 'sendmail' => [ 60 | 'transport' => 'sendmail', 61 | 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -t -i'), 62 | ], 63 | 64 | 'log' => [ 65 | 'transport' => 'log', 66 | 'channel' => env('MAIL_LOG_CHANNEL'), 67 | ], 68 | 69 | 'array' => [ 70 | 'transport' => 'array', 71 | ], 72 | 73 | 'failover' => [ 74 | 'transport' => 'failover', 75 | 'mailers' => [ 76 | 'smtp', 77 | 'log', 78 | ], 79 | ], 80 | ], 81 | 82 | /* 83 | |-------------------------------------------------------------------------- 84 | | Global "From" Address 85 | |-------------------------------------------------------------------------- 86 | | 87 | | You may wish for all e-mails sent by your application to be sent from 88 | | the same address. Here, you may specify a name and address that is 89 | | used globally for all e-mails that are sent by your application. 90 | | 91 | */ 92 | 93 | 'from' => [ 94 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 95 | 'name' => env('MAIL_FROM_NAME', 'Example'), 96 | ], 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Markdown Mail Settings 101 | |-------------------------------------------------------------------------- 102 | | 103 | | If you are using Markdown based email rendering, you may configure your 104 | | theme and component paths here, allowing you to customize the design 105 | | of the emails. Or, you may simply stick with the Laravel defaults! 106 | | 107 | */ 108 | 109 | 'markdown' => [ 110 | 'theme' => 'default', 111 | 112 | 'paths' => [ 113 | resource_path('views/vendor/mail'), 114 | ], 115 | ], 116 | 117 | ]; 118 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | bootstrap(); 8 | 9 | date_default_timezone_set(env('APP_TIMEZONE', 'UTC')); 10 | 11 | /* 12 | |-------------------------------------------------------------------------- 13 | | Create The Application 14 | |-------------------------------------------------------------------------- 15 | | 16 | | Here we will load the environment and create the application instance 17 | | that serves as the central piece of this framework. We'll use this 18 | | application as an "IoC" container and router for this framework. 19 | | 20 | */ 21 | 22 | $app = new Laravel\Lumen\Application( 23 | dirname(__DIR__) 24 | ); 25 | 26 | $app->withFacades(); 27 | 28 | $app->configure('filesystems'); 29 | 30 | $app->withEloquent(); 31 | 32 | /* 33 | |-------------------------------------------------------------------------- 34 | | Register Container Bindings 35 | |-------------------------------------------------------------------------- 36 | | 37 | | Now we will register a few bindings in the service container. We will 38 | | register the exception handler and the console kernel. You may add 39 | | your own bindings here if you like or you can make another file. 40 | | 41 | */ 42 | 43 | $app->singleton( 44 | Illuminate\Contracts\Debug\ExceptionHandler::class, 45 | App\Exceptions\Handler::class 46 | ); 47 | 48 | $app->singleton( 49 | Illuminate\Contracts\Console\Kernel::class, 50 | App\Console\Kernel::class 51 | ); 52 | 53 | 54 | /* 55 | |-------------------------------------------------------------------------- 56 | | Register Config Files 57 | |-------------------------------------------------------------------------- 58 | | 59 | | Now we will register the "app" configuration file. If the file exists in 60 | | your configuration directory it will be loaded; otherwise, we'll load 61 | | the default version. You may register other files below as needed. 62 | | 63 | */ 64 | 65 | $app->configure('app'); 66 | 67 | 68 | /* 69 | |-------------------------------------------------------------------------- 70 | | Register Middleware 71 | |-------------------------------------------------------------------------- 72 | | 73 | | Next, we will register the middleware with the application. These can 74 | | be global middleware that run before and after each request into a 75 | | route or middleware that'll be assigned to some specific routes. 76 | | 77 | */ 78 | 79 | $app->middleware([ 80 | App\Http\Middleware\CorsMiddleware::class 81 | ]); 82 | 83 | $app->routeMiddleware([ 84 | 'auth' => App\Http\Middleware\Authenticate::class, 85 | ]); 86 | 87 | /* 88 | 89 | $app->middleware([ 90 | App\Http\Middleware\OldMiddleware::class 91 | ]); 92 | 93 | $app->routeMiddleware([ 94 | 'auth' => App\Http\Middleware\Authenticate::class, 95 | ]); 96 | */ 97 | /* 98 | |-------------------------------------------------------------------------- 99 | | Register Service Providers 100 | |-------------------------------------------------------------------------- 101 | | 102 | | Here we will register all of the application's service providers which 103 | | are used to bind services into the container. Service providers are 104 | | totally optional, so you are not required to uncomment this line. 105 | | 106 | */ 107 | 108 | // $app->register(App\Providers\AppServiceProvider::class); 109 | // $app->register(App\Providers\AuthServiceProvider::class); 110 | // $app->register(App\Providers\EventServiceProvider::class); 111 | $app->register(Illuminate\Filesystem\FilesystemServiceProvider::class); 112 | //internal Soap needed on some installs 113 | //$app->register(Artisaninweb\SoapWrapper\ServiceProvider::class); 114 | //class_alias('Artisaninweb\SoapWrapper\Facade', 'SoapWrapper'); 115 | 116 | $app->register(Illuminate\Mail\MailServiceProvider::class); 117 | 118 | $app->configure('mail'); 119 | $app->alias('mailer', Illuminate\Mail\Mailer::class); 120 | $app->alias('mailer', Illuminate\Contracts\Mail\Mailer::class); 121 | $app->alias('mailer', Illuminate\Contracts\Mail\MailQueue::class); 122 | 123 | /* 124 | |-------------------------------------------------------------------------- 125 | | Load The Application Routes 126 | |-------------------------------------------------------------------------- 127 | | 128 | | Next we will include the routes file so that they can all be added to 129 | | the application. This will provide all of the URLs the application 130 | | can respond to, as well as the controllers that may handle them. 131 | | 132 | */ 133 | 134 | $app->router->group([ 135 | 'namespace' => 'App\Http\Controllers', 136 | ], function ($router) { 137 | require __DIR__.'/../routes/web.php'; 138 | }); 139 | 140 | return $app; 141 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | get('/', ['uses' => 'HelpController@showHelpMain']); 12 | $router->get('/help', ['uses' => 'HelpController@showHelpMain']); 13 | $router->get('/version', function () use ($router) { 14 | return $router->app->version() ; 15 | }); 16 | $router->post('login', ['uses' => 'UserController@login']); //TODO remove 17 | 18 | /*$router->get('admin/profile', ['middleware' => 'auth', function () { 19 | // 20 | }]);*/ 21 | 22 | $router->get('help', ['uses' => 'HelpController@showHelpMain']); 23 | 24 | //Users routes 25 | $router->group(['prefix' => '/user'], function () use ($router) { 26 | $router->post('recover', ['uses' => 'UserController@recoverPassword']); 27 | $router->get('', ['uses' => 'UserController@showAllUsers']); 28 | $router->get('{id}', ['uses' => 'UserController@showOneUser']); 29 | $router->post('', ['uses' => 'UserController@create']); 30 | $router->post('{id}', ['uses' => 'UserController@update']); 31 | $router->delete('{id}/{mail}', ['uses' => 'UserController@delete']); 32 | }); 33 | 34 | // Messages routes 35 | $router->get('/unpack/{arg}', ['uses' => 'MessageController@unpackInboxMessage']); 36 | $router->get('/mail', ['uses' => 'MessageController@mailtoall']); 37 | $router->get('/messages', ['uses' => 'MessageController@showAllMessages']); 38 | $router->get('/messages/{type}', ['uses' => 'MessageController@showAllMessagesByType']); 39 | 40 | $router->group(['prefix' => '/message'], function () use ($router) { 41 | $router->get('', ['uses' => 'MessageController@showAllMessages']); 42 | $router->get('list', ['uses' => '@showAllMessages']); 43 | $router->get('{id}', ['uses' => 'MessageController@showOneMessage']); 44 | $router->get('image/{id}', ['uses' => 'FileController@get']); 45 | $router->get('send/{id}', ['uses' => 'MessageController@sendMessage']); 46 | $router->post('', ['uses' => 'MessageController@sendHMP']); 47 | $router->post('{id}', ['uses' => 'MessageController@update']); 48 | $router->delete('{id}', ['uses' => 'MessageController@deleteMessage']); 49 | }); 50 | 51 | $router->group(['prefix' => '/inbox'], function () use ($router) { 52 | $router->get('', ['uses' => 'MessageController@showAllInboxMessages']); 53 | $router->get('{id}', ['uses' => 'MessageController@showOneInboxMessage']); 54 | $router->get('delete/{id}', ['uses' => 'MessageController@deleteInboxMessage']); 55 | $router->get('hide/{id}', ['uses' => 'MessageController@hideInboxMessage']); 56 | $router->get('unhide/{id}', ['uses' => 'MessageController@unhideInboxMessage']); 57 | $router->post('uncrypt/{id}', ['uses' => 'MessageController@unCrypt']); 58 | }); 59 | 60 | // file upload, download, crypt, compress, uncompress 61 | $router->group(['prefix' => '/file'], function () use ($router) { 62 | $router->get('{file}', ['uses' => 'FileController@downloadFile']); 63 | $router->post('', ['uses' => 'FileController@uploadFile']); 64 | $router->delete('', ['uses' => 'FileController@deleteLostFiles']); 65 | //TODO 66 | // $router->get('', ['uses' => 'FileController@showAllFiles']); 67 | }); 68 | 69 | // system commands 70 | 71 | $router->group(['prefix' => '/sys'], function () use ($router) { 72 | $router->get('', ['uses' => 'SystemController@getSysStatus']); //double hit for status 73 | $router->get('config', ['uses' => 'SystemController@getSysConfig']); 74 | $router->post('config', ['uses' => 'SystemController@setSysConfig']); 75 | $router->get('gw', ['uses' => 'SystemController@getSysGw']); 76 | $router->get('nodename', ['uses' => 'SystemController@getSysNodeName']); 77 | $router->get('queueerase', ['uses' => 'SystemController@queueErase']); 78 | $router->get('ls', ['uses' => 'SystemController@getFiles']); 79 | $router->get('list', ['uses' => 'SystemController@systemDirList']); 80 | $router->post('login', ['uses' => 'UserController@login']); 81 | $router->get('maildu', ['uses' => 'SystemController@getMailDiskUsage']); 82 | $router->get('maillog', ['uses' => 'SystemController@sysLogMail']); 83 | $router->get('run/{command}', ['uses' => 'SystemController@exec_cli']); 84 | $router->get('stations', ['uses' => 'SystemController@getSysStations']); 85 | $router->get('status', ['uses' => 'SystemController@getSysStatus']); 86 | $router->get('sensors', ['uses' => 'SystemController@getSensors']); 87 | $router->get('uuls', ['uses' => 'SystemController@sysGetSpoolList']); 88 | $router->delete('uuka', ['uses' => 'SystemController@uucpKillJobs']); 89 | $router->delete('mail/{host}/{id}', ['uses' => 'SystemController@uucpKillMail']); 90 | $router->delete('uuk/{host}/{id}', ['uses' => 'SystemController@uucpKillJob']); 91 | $router->get('uucall', ['uses' => 'SystemController@uucpCall']); 92 | $router->get('uulog', ['uses' => 'SystemController@sysLogUucp']); 93 | $router->get('uudebug', ['uses' => 'SystemController@sysDebUucp']); 94 | $router->get('shutdown', ['uses' => 'SystemController@sysShutdown']); 95 | $router->get('restart', ['uses' => 'SystemController@sysRestart']); 96 | $router->get('reboot', ['uses' => 'SystemController@sysReboot']); 97 | // $router->get('restore', ['uses' => 'SystemController@sysRestore']); 98 | }); 99 | 100 | $router->group(['prefix' => '/caller'], function () use ($router) { 101 | $router->get('', ['uses' => 'CallerController@showAll']); 102 | $router->post('', ['uses' => 'CallerController@createSched']); 103 | $router->put('{id}', ['uses' => 'CallerController@updateSched']); 104 | $router->get('{id}', ['uses' => 'CallerController@showSched']); 105 | $router->delete('{id}', ['uses' => 'CallerController@deleteSched']); 106 | }); 107 | 108 | $router->group(['prefix' => '/radio'], function () use ($router) { 109 | $router->get('', ['uses' => 'RadioController@getRadioStatus']); 110 | $router->get('power', ['uses' => 'RadioController@getRadioPowerStatus']); 111 | $router->get('mode', ['uses' => 'RadioController@getRadioMode']); 112 | $router->post('mode/{mode}', ['uses' => 'RadioController@setRadioMode']); 113 | $router->get('freq', ['uses' => 'RadioController@getRadioFreq']); 114 | $router->post('freq/{freq}', ['uses' => 'RadioController@setRadioFreq']); 115 | $router->get('bfo', ['uses' => 'RadioController@getRadioBfo']); 116 | $router->post('bfo/{freq}', ['uses' => 'RadioController@setRadioBfo']); 117 | $router->get('fwd', ['uses' => 'RadioController@getRadioFwd']); 118 | //$router->post('fwd/{freq}', ['uses' => 'RadioController@setRadioFwd']); 119 | $router->get('led', ['uses' => 'RadioController@getRadioLedStatus']); 120 | $router->post('led/{status}', ['uses' => 'RadioController@setRadioLedStatus']); 121 | $router->get('ref', ['uses' => 'RadioController@getRadioRef']); 122 | $router->post('ptt/{status}', ['uses' => 'RadioController@setRadioPtt']); 123 | $router->post('tone/{par}', ['uses' => 'RadioController@setRadioTone']); 124 | //$router->post('ref/{freq}', ['uses' => 'RadioController@setRadioRef']); 125 | $router->get('txrx', ['uses' => 'RadioController@getRadioTxrx']); 126 | $router->get('mastercal', ['uses' => 'RadioController@getRadioMasterCal']); 127 | $router->post('mastercal/{freq}', ['uses' => 'RadioController@setRadioMasterCal']); 128 | $router->get('protection', ['uses' => 'RadioController@getRadioProtection']); 129 | $router->get('connection', ['uses' => 'RadioController@getRadioConnectionStatus']); 130 | $router->post('connection/{status}', ['uses' => 'RadioController@setRadioConnectionStatus']); 131 | $router->get('serial', ['uses' => 'RadioController@getRadioSerial']); 132 | $router->get('refthreshold', ['uses' => 'RadioController@getRadioRefThreshold']); 133 | $router->post('refthreshold/{value}', ['uses' => 'RadioController@setRadioRefThreshold']); 134 | $router->post('refthresholdv/{value}', ['uses' => 'RadioController@setRadioRefThresholdV']); 135 | $router->post('protection', ['uses' => 'RadioController@resetRadioProtection']); 136 | $router->post('setdefaults', ['uses' => 'RadioController@setRadioDefaults']); 137 | $router->post('restoredefaults', ['uses' => 'RadioController@restoreRadioDefaults']); 138 | }); 139 | 140 | 141 | $router->group(['prefix' => '/geolocation'], function () use ($router) { 142 | $router->get('calibration', ['uses' => 'GeoLocationController@startGPSCalibration']); 143 | }); 144 | -------------------------------------------------------------------------------- /app/Http/Controllers/FileController.php: -------------------------------------------------------------------------------- 1 | validate($request, [ 28 | //TODO check if really need this 29 | //'fileup' => 'required|file|max:' . env('MAX_FILE_SIZE') . '| mimes:jpg,png,ogg,mp3,mp4,wav', 30 | 'fileup' => 'required|file', 31 | 'pass' => 'min:4|max:20', 32 | ]); 33 | 34 | $timestamp=time(); 35 | // get the file and info 36 | $file = $request->file('fileup'); 37 | $filename = $file->getClientOriginalName(); 38 | $mimetype = $file->getMimeType(); 39 | 40 | // set internal path 41 | $origpath = 'tmp/'.$timestamp; 42 | 43 | // set external path 44 | $path = ''; 45 | $imageout = '.vvc'; 46 | $audioout = '.lpcnet'; 47 | $gpgout = '.gpg'; 48 | 49 | // get contents of the file on request 50 | if( $contents = file_get_contents($request->fileup)){ 51 | // Write a new file in tmp with a timestamp with contents 52 | if ( Storage::disk('local')->put($origpath, $contents)){ 53 | $path = Storage::disk('local')->path($origpath); 54 | 55 | // check for file types 56 | // compress image 57 | if (preg_match("/\bimage\b/i", $mimetype)) { 58 | $command = 'compress_image.sh ' . $path . ' ' . $path.$imageout; 59 | $output = exec_cli($command); 60 | $filesize = explode(":", explode("\n",$output)[5])[1]; 61 | 62 | // delete original file 63 | if ( !Storage::disk('local')->delete($origpath) ) { 64 | return response()->json(['message' => 'API: fileup error on delete original image file ' . $path], 500); 65 | } 66 | $origpath= $origpath.$imageout; 67 | $path = Storage::disk('local')->path($origpath); 68 | } 69 | // compress audio - script supports wav mp3 or acc 70 | elseif (preg_match("/\baudio\b/i", $mimetype)) { 71 | $command = 'compress_audio.sh ' . $path . ' ' . $path.$audioout;; 72 | $output = exec_cli($command); 73 | $path = Storage::disk('local')->path($origpath); 74 | 75 | $filesize = explode(":", explode("\n",$output)[0])[1]; 76 | 77 | // delete original file 78 | if ( Storage::disk('local')->delete($origpath) ) { 79 | $origpath= $origpath.$audioout; 80 | $path = Storage::disk('local')->path($origpath); 81 | } 82 | else{ 83 | return response()->json(['message' => 'API: fileup error on delete original audio file ' . $path], 500); 84 | } 85 | } 86 | } 87 | else{ 88 | return response()->json(['message' => 'API: fileup error on write file' . 'tmp/' . $timestamp], 500); 89 | } 90 | } 91 | else{ 92 | return response()->json(['message' => 'API: fileup error fileup is a file?'], 500); 93 | } 94 | 95 | // secure the file 96 | if ($request->pass && $request->pass != 'undefined'){ 97 | $command = 'gpg -o '. $path . '.gpg -c --cipher-algo AES256 --symmetric --batch --passphrase "' . $request->pass. '" --yes ' . $path; 98 | if ($output = exec_cli_no($command) ){ 99 | if ( ! Storage::disk('local')->delete($origpath) ) { 100 | return response()->json(['message' => 'API: fileup error on delete original file ' . $path], 500); 101 | } 102 | $origpath= $origpath.$gpgout; 103 | } 104 | else { 105 | return response()->json(['message' => 'API: fileup error on encrypt the file: ' ], 500); 106 | } 107 | $secure=true; 108 | } 109 | else{ 110 | $secure = 'none'; 111 | } 112 | 113 | // Test and create uploads folder if it doesn't exists 114 | if (! Storage::disk('local')->exists('uploads')){ 115 | if(!Storage::disk('local')->makeDirectory('uploads')){ 116 | return response()->json(['message' => 'API: Error, can\'t find or create uploads dir'], 500); 117 | } 118 | } 119 | 120 | // move the file 121 | $internalfilename = explode('/', $origpath)[1]; 122 | $uploadpath = 'uploads/' . $internalfilename; 123 | if (Storage::disk('local')->move($origpath, $uploadpath)) { 124 | $filesize = Storage::disk('local')->size($uploadpath); 125 | $path = Storage::disk('local')->path($uploadpath); 126 | } 127 | else{ 128 | return response()->json(['message' => 'API: fileup error, couldnt complete and move the file: ' ], 500); 129 | } 130 | 131 | // Log fileup 132 | Log::info('API file upload: '. $filename . ' - ' . $internalfilename); 133 | 134 | //finish and show return status 135 | return response()->json([ 136 | 'message' => 'API fileup OK', 137 | // 'command' => $command, 138 | 'filename' => $filename, 139 | 'id' => $internalfilename, 140 | 'mimetype' => $mimetype, 141 | //'origpath' => $origpath, 142 | //'serverpath' => $path, 143 | 'filesize' => $filesize, 144 | 'secure' => $secure, 145 | ], 200); 146 | } // end uploadFile 147 | 148 | /** 149 | * downloadFile 150 | * parameter: message id 151 | * @return Json 152 | */ 153 | public static function downloadFile($file) 154 | { 155 | // check for password 156 | request()->has('i') ? $pass=request()->i : null; 157 | 158 | //get message from file 159 | $message = Message::where('fileid', '=', $file)->latest('id')->first(); 160 | 161 | // get timestamp 162 | $timestamp = explode('.', $file)[0]; 163 | 164 | // handle real file extensions 165 | if (! isset(explode('.', $file)[1])){ 166 | $fileext = ''; 167 | } 168 | else{ 169 | $fileext = '.' . explode('.', $file)[1]; 170 | } 171 | 172 | // handle file nameextension 173 | $countdot = count(explode('.', $message->file)); 174 | if ($countdot > 1){ 175 | if ($countdot > 1){ 176 | $decompressext = '.' . explode('.', $message->file)[$countdot-1]; 177 | } 178 | else { 179 | $decompressext = '.' . explode('.', $message->file)[1]; 180 | } 181 | } 182 | 183 | // set path 184 | if ($message->inbox){ 185 | $origpath = 'downloads/' . $file; 186 | } 187 | else{ 188 | $origpath = 'uploads/' . $file; 189 | } 190 | 191 | // get file path 192 | $path = Storage::disk('local')->path($origpath); 193 | $fullpathroot = Storage::disk('local')->path('/'); 194 | 195 | // verify if file is GPG cryptedj 196 | $crypt = false; 197 | // teste if message is secure and pass (i) exists 198 | if ( $message->secure && $pass ){ 199 | $fullpath = $fullpathroot . 'tmp/' . $timestamp . $fileext; 200 | $gppath = Storage::disk('local')->path('/'); 201 | $command = 'gpg -o '. $fullpath . ' -d --batch --passphrase "' . $pass . '" --yes ' . $path; 202 | exec_cli_no($command); 203 | $crypt = true; 204 | $origpath = 'tmp/' . $timestamp .$fileext; 205 | } 206 | 207 | // verify if file is image and decompress 208 | if (preg_match("/\bvvc\b/i", $file)) { 209 | $fullpath = $fullpathroot . $origpath; 210 | // decompress image 211 | $command = 'decompress_image.sh ' . $fullpath . ' ' . $fullpath . $decompressext; 212 | // print "DEBUG uncompress command: " . $command. "\n"; 213 | if( exec_cli_no($command)){ 214 | $origpath = $origpath . $decompressext; 215 | $path = Storage::disk('local')->path($origpath); 216 | } 217 | else{ 218 | return response()->json(['message' => 'API: download uncompres image error: ' ], 500); 219 | } 220 | // get content of file 221 | $content = Storage::disk('local')->get($origpath); 222 | 223 | // delete generated file 224 | Storage::disk('local')->delete($origpath); 225 | return response($content) 226 | ->header('Content-Type',$message->mimetype) 227 | ->header('Pragma','public') 228 | ->header('Content-Disposition','inline; filename="'. $message->file) 229 | ->header('Cache-Control','max-age=60, must-revalidate'); 230 | } 231 | // verify if file is audio - LPCNET and decompress 232 | elseif (preg_match("/\blpcnet\b/i", $file)) { 233 | $fullpath = $fullpathroot . $origpath; 234 | // decompress audio 235 | // mount command to decompress audio 236 | $command = 'decompress_audio.sh ' . $fullpath . ' ' . $fullpath . $decompressext;; 237 | $fullpath .= $decompressext; 238 | 239 | // decompress audio 240 | if( exec_cli_no($command)){ 241 | $origpath = $origpath . $decompressext; 242 | $path = Storage::disk('local')->path($origpath); 243 | } 244 | else{ 245 | return response()->json(['message' => 'API: download uncompres audio error: ' ], 500); 246 | } 247 | 248 | // get content of file 249 | $content = Storage::disk('local')->get($origpath); 250 | // delete generated file 251 | Storage::disk('local')->delete($origpath); 252 | // return response($content); 253 | return response($content) 254 | ->header('Content-Type', $message->mimetype) 255 | ->header('Pragma','public') 256 | ->header('Content-Disposition','inline; filename="'. $message->file) 257 | ->header('Cache-Control','max-age=60, must-revalidate'); 258 | } 259 | else { 260 | // $fullpath = $fullpathroot . $origpath; 261 | $content = Storage::disk('local')->get($origpath); 262 | return response($content) 263 | ->header('Content-Type', $message->mimetype) 264 | ->header('Pragma','public') 265 | ->header('Content-Disposition','inline; filename="'. $message->file) 266 | ->header('Cache-Control','max-age=60, must-revalidate'); 267 | } 268 | } 269 | 270 | /** 271 | * cleanLostFiles 272 | * parameter: message id 273 | * @return Json 274 | */ 275 | public static function deleteLostFiles() 276 | { 277 | 278 | // list files on upload 279 | $list = ['uploads', 'downloads']; 280 | 281 | foreach ($list as $path){ 282 | 283 | $files = Storage::disk('local')->files($path); 284 | foreach ($files as $file){ 285 | if (! Message::where('fileid', '=', explode($path . '/', $file)[1])->first()){ 286 | $output[] = $file; 287 | Storage::disk('local')->delete($file); 288 | } 289 | 290 | print "\n"; 291 | } 292 | } 293 | Storage::disk('local')->deleteDirectory('outbox'); 294 | Storage::disk('local')->deleteDirectory('tmp'); 295 | 296 | return response()->json(['message' => 'delete Lost files, outbox and tmp' . $path], 200); 297 | } 298 | 299 | } 300 | -------------------------------------------------------------------------------- /app/Http/Controllers/UserController.php: -------------------------------------------------------------------------------- 1 | json(User::all()); 14 | } 15 | 16 | public function showOneUser($id) 17 | { 18 | if (! $user = User::firstWhere('email', $id)) { 19 | return response()->json(['message' => 'API showoneuser error, cant find'], 404); 20 | } 21 | else{ 22 | return response()->json($user, 200); 23 | } 24 | } 25 | 26 | public function create(Request $request) 27 | { 28 | //var_dump($request->all); 29 | $username = env('HERMES_EMAILAPI_USER'); 30 | $password = env('HERMES_EMAILAPI_PASS'); 31 | $soap_location = env('HERMES_EMAILAPI_LOC'); 32 | $soap_uri = env('HERMES_EMAILAPI_URI'); 33 | 34 | $client = new \SoapClient(null, array('location' => $soap_location, 35 | 'uri' => $soap_uri, 36 | 'trace' => 1, 37 | 'stream_context'=> stream_context_create(array('ssl'=> array('verify_peer'=>false,'verify_peer_name'=>false))), 38 | 'exceptions' => 1)); 39 | try { 40 | if ( $session_id = $client->login($username, $password)) { 41 | //Logged successfull. Session ID:'.$session_id.'
'; 42 | //, 'phone', 'site', 'location', 'password', 'recoverphrase', 'recoveranswer', 'updated_at', 'created_at', 'admin' 43 | //* Set the function parameters. 44 | $client_id = 1; 45 | $request['email'] = strtolower($request['email']); 46 | $params = array( 47 | 'server_id' => 1, 48 | 'email' => $request['email'] . '@' . env('HERMES_DOMAIN'), 49 | 'login' => $request['email'], 50 | 'password' => $request['password'], 51 | 'name' => $request['name'], 52 | 'uid' => 5000, 53 | 'gid' => 5000, 54 | 'maildir' => '/var/vmail/' . $request['email'], 55 | 'quota' => 0, 56 | 'cc' => '', 57 | 'homedir' => '/var/vmail', 58 | 'autoresponder' => 'n', 59 | 'autoresponder_start_date' => '', 60 | 'autoresponder_end_date' => '', 61 | 'autoresponder_text' => NULL, 62 | 'autoresponder_subject' => 'Out of village reply', 63 | 'move_junk' => 'n', 64 | 'custom_mailfilter' => 'spam', 65 | 'postfix' => 'y', 66 | 'access' => 'y', 67 | 'disableimap' => 'n', 68 | 'disablepop3' => 'n', 69 | 'disabledeliver' => 'n', 70 | 'disablesmtp' => 'n', 71 | 'dbispconfig' => 1, 72 | 'mail_user' => 0, 73 | 'purge_trash_days' => 100, 74 | 'purge_junk_days' => 100 75 | ); 76 | 77 | //* Call the SOAP method 78 | if (! $mailuser_id = $client->mail_user_add($session_id, $client_id, $params)) { 79 | $client->logout($session_id); 80 | return response()->json(['message' => 'API create user error: cant create email'], 500); 81 | } 82 | $request['pass'] = $request['password']; 83 | $request['password'] = hash('sha256', $request['password']); 84 | $request['emailid'] = $mailuser_id; 85 | 86 | if (! $user = User::create($request->all())) { 87 | $client->logout($session_id); 88 | return response()->json(['message' => 'API create user error: cant create user'], 500); 89 | } 90 | 91 | // forward 92 | if ($forwarding_id = env('HERMES_EMAILAPI_FORWARDING_ID')){ 93 | $mail_forward = $client->mail_forward_get($session_id, $forwarding_id); 94 | $find = strpos($mail_forward['destination'], $request['email']); 95 | if ($find === false) { 96 | $mail_forward['destination'] .= ', ' . $request['email'] . '@' . env('HERMES_DOMAIN'); 97 | $client->mail_forward_update($session_id, $client_id, $forwarding_id, $mail_forward); 98 | } 99 | } 100 | 101 | // call the uuadm 102 | $command = "uux -j -r '" . env('HERMES_ROUTE') . "!uuadm -a -m " . $request['email'] . "@" . env('HERMES_DOMAIN') . " -p " . $request['pass'] . " -n " . $request['name'] . "'" ; 103 | if (! $output = exec_cli($command)) { 104 | $client->logout($session_id); 105 | return response()->json(['message' => 'API create user error: cant advise to central'], 500); 106 | } 107 | else { 108 | //returns uucp job id 109 | $output = explode("\n", $output)[0]; 110 | $client->logout($session_id); 111 | return response()->json($output, 201); //Created 112 | } 113 | } 114 | } 115 | catch (SoapFault $e) { 116 | echo $client->__getLastResponse(); 117 | die('SOAP Error: '.$e->getMessage()); 118 | } 119 | } // end of create function 120 | 121 | 122 | public function update($id, Request $request) 123 | { 124 | 125 | //some tests 126 | if($id == 'root'){ 127 | return response()->json(['message' => 'API update user error: cant update root'], 500); 128 | } 129 | 130 | if( $request['email']){ 131 | return response()->json(['message' => 'API update user error: cant change an existing login email'], 500); 132 | } 133 | 134 | if (! $request[ 'name'] && ! $request[ 'password'] && ! $request[ 'phone'] && ! $request[ 'site'] && ! $request[ 'location'] && ! $request[ 'recoverphrase'] && ! $request[ 'recoveranswer'] && ! $request[ 'admin'] ){ 135 | return response()->json('Error: cant update without data form ', 504); 136 | } 137 | $username = env('HERMES_EMAILAPI_USER'); 138 | $password = env('HERMES_EMAILAPI_PASS'); 139 | $soap_location = env('HERMES_EMAILAPI_LOC'); 140 | $soap_uri = env('HERMES_EMAILAPI_URI'); 141 | 142 | $client = new \SoapClient(null, array('location' => $soap_location, 143 | 'uri' => $soap_uri, 144 | 'trace' => 1, 145 | 'stream_context'=> stream_context_create(array('ssl'=> array('verify_peer'=>false,'verify_peer_name'=>false))), 146 | 'exceptions' => 1)); 147 | 148 | try { 149 | if($session_id = $client->login($username, $password)) { 150 | 151 | // Get the email user record 152 | $mail_user_record = $client->mail_user_get($session_id, $id); 153 | 154 | if ($request['name']){ 155 | $mail_user_record['name'] = $request['name']; 156 | } 157 | 158 | if ($request['password']){ 159 | $mail_user_record['password'] = $request['password']; 160 | } 161 | 162 | if ($request['phone']){ 163 | $mail_user_record['phone'] = $request['phone']; 164 | } 165 | 166 | $client_id = 1; 167 | //Update the email record 168 | $affected_rows = $client->mail_user_update($session_id, $client_id, $id, $mail_user_record); 169 | 170 | //disconnect SOAP 171 | $client->logout($session_id); 172 | $login = $mail_user_record['login']; 173 | if ($affected_rows <= 0) { 174 | return response()->json(['message' => 'API update user error: cant update'], 501); 175 | } 176 | if (! $user = User::firstWhere('email', $login)) { 177 | return response()->json('Error: mail id not found on database', 504); 178 | } 179 | if ($request['password']){ 180 | $request['password'] = hash('sha256', $request['password']); 181 | } 182 | 183 | if (! User::where('email', $login)->update($request->all())) { 184 | return response()->json(['message' => 'API update error: ispconfig updated but not local database'], 501); 185 | } 186 | $user = User::firstWhere('email', $login); 187 | return response()->json( $user, 200); 188 | } 189 | } catch (SoapFault $e) { 190 | echo $client->__getLastResponse(); 191 | die('SOAP Error: '.$e->getMessage()); 192 | } 193 | } // end of update function 194 | 195 | public function delete($id,$mail) 196 | { 197 | if($id == 'root'){ 198 | return response()->json('Error: cant delete system user root', 504); 199 | } 200 | $username = env('HERMES_EMAILAPI_USER'); 201 | $password = env('HERMES_EMAILAPI_PASS'); 202 | $soap_location = env('HERMES_EMAILAPI_LOC'); 203 | $soap_uri = env('HERMES_EMAILAPI_URI'); 204 | $client = new \SoapClient(null, array('location' => $soap_location, 205 | 'uri' => $soap_uri, 206 | 'trace' => 1, 207 | 'stream_context'=> stream_context_create(array('ssl'=> array('verify_peer'=>false,'verify_peer_name'=>false))), 208 | 'exceptions' => 1)); 209 | try { 210 | if ( $session_id = $client->login($username, $password)) { 211 | // Parameters 212 | $affected_rows = $client->mail_user_delete($session_id, $id); 213 | 214 | if ($affected_rows <= 0) { 215 | return response()->json(['message' => 'API user delete error - cant remove email from server'], 405); 216 | } 217 | if (! User::firstWhere('email', $mail)) { 218 | return response()->json(['message' => 'API user delete error - cant find user'], 404); 219 | } 220 | if (!User::where('email', $mail)->delete()) { 221 | return response()->json(['message' => 'API user delete error '], 500); 222 | } 223 | $command = "uux -j -r '" . env('HERMES_ROUTE') . "!uuadm -d -m " . $mail . '@' . env('HERMES_DOMAIN') . "'" ; 224 | //TOOD check that 225 | $output = exec_cli($command); 226 | // if ($output = exec_cli($command)) { 227 | // return response()->json(['message' => 'API user delete error on uux'], 300); 228 | // } 229 | //returns uucp job id 230 | $uucp_job_id= explode("\n", $output)[0]; 231 | 232 | if ($forwarding_id = env('HERMES_EMAILAPI_FORWARDING_ID')){ 233 | $client_id = 1; 234 | $mail_forward = $client->mail_forward_get($session_id, $forwarding_id); 235 | $find = strpos($mail_forward['destination'], $mail); 236 | if ($find !== false) { 237 | $destination = explode(', ', $mail_forward['destination']); 238 | $new_destination = []; 239 | //remove 240 | foreach ( $destination as $key => $value) { 241 | if ($value != $mail . "@" . env('HERMES_DOMAIN') ) { 242 | array_push($new_destination, $value) ; 243 | } 244 | } 245 | $mail_forward['destination'] = ''; 246 | for($i = 0; $i < count($new_destination); $i++) { 247 | 248 | if (count($new_destination)-1 == $i) { 249 | $mail_forward['destination'] .= $new_destination[$i]; 250 | } 251 | else{ 252 | $mail_forward['destination'] .= $new_destination[$i] . ', '; 253 | } 254 | } 255 | $client->mail_forward_update($session_id, $client_id, $forwarding_id, $mail_forward); 256 | } 257 | } 258 | 259 | $client->logout($session_id); 260 | 261 | return response()->json($uucp_job_id , 200); 262 | } 263 | } catch (SoapFault $e) { 264 | echo $client->__getLastResponse(); 265 | die('SOAP Error: '.$e->getMessage()); 266 | } 267 | } 268 | 269 | /** 270 | * login 271 | * parameter: $request with email and password 272 | * @return Json 273 | */ 274 | public function login(Request $request) 275 | { 276 | $user = new User; 277 | if (! $request->email) { 278 | return response()->json(['message' => 'API user login - lack parameters'], 412); 279 | } 280 | if (! $user = User::firstWhere('email', $request->email)) { 281 | return response()->json(['message' => 'API user login - wrong user'], 404); 282 | } 283 | if ($user['password'] !== hash('sha256', $request->password)){ //sucessfull login 284 | return response()->json(['message' => 'API user login - wrong password'], 420); 285 | } 286 | else{ 287 | unset($user['password']); 288 | unset($user['recoverphrase']); 289 | unset($user['recoveranswer']); 290 | unset($user['created_at']); 291 | unset($user['updated_at']); 292 | return response()->json($user, 200); 293 | } 294 | } 295 | 296 | /** 297 | * recover password 298 | * parameter: $request with email and recoveranswer 299 | * @return Json 300 | */ 301 | 302 | public function recoverPassword(Request $request) 303 | { 304 | $user = new User; 305 | if (! $request->email) { 306 | return response()->json(['message' => 'API user recover - lack parameters'], 412); 307 | } 308 | if (! $user = User::firstWhere('email', $request->email)) { 309 | return response()->json(['message' => 'API user recover - wrong user'], 404); 310 | } 311 | 312 | if ($user['recoveranswer'] != $request->recoveranswer){ //sucessfull 313 | return response()->json(['message' => 'API user recover - wrong answer'], 420); 314 | } 315 | else{ 316 | 317 | // unset($user['password']); 318 | // unset($user['recoverphrase']); 319 | // unset($user['recoveranswer']); 320 | // unset($user['created_at']); 321 | // unset($user['updated_at']); 322 | return response()->json($user, 200); 323 | } 324 | } // end of delete function 325 | } -------------------------------------------------------------------------------- /app/Http/Controllers/SystemController.php: -------------------------------------------------------------------------------- 1 | nodename = explode("\n", exec_cli("cat /etc/uucp/config|grep nodename|cut -f 2 -d \" \""))[0]; 21 | return response()->json($system,200); 22 | } 23 | 24 | public function setSysConfig(Request $request) 25 | { 26 | if ($request->all()){ 27 | if (System::select()->update($request->all())){ 28 | return response()->json($request->all() , 200); 29 | } 30 | else { 31 | return response()->json(['message' => 'setSysConfig can not update' ], 500); 32 | } 33 | } 34 | else { 35 | return response()->json(['message' => 'setSysConfig does not have request data'], 500); 36 | } 37 | } 38 | 39 | /** 40 | * returns if station is a gateway 41 | * 42 | * @return string 43 | */ 44 | public function getSysGw() 45 | { 46 | $gateway = env('HERMES_GATEWAY') ; 47 | return response()->json($gateway,200); 48 | } 49 | 50 | /** 51 | * set gw schedule 52 | * 53 | * @return string 54 | */ 55 | public function setSysGwSched(Request $request) 56 | { 57 | if ($request->all()){ 58 | return response()->json(['message' => 'setSysGw TODO'], 200); 59 | } 60 | else { 61 | return response()->json(['message' => 'setSysConfig does not have request data'], 500); 62 | } 63 | } 64 | 65 | /** 66 | * Get Name station from uucp 67 | * 68 | * @return string 69 | */ 70 | public function getSysNodeName() 71 | { 72 | return response(json_encode(exec_nodename()),200); 73 | } 74 | 75 | /** 76 | * Get system status 77 | * 78 | * @return Table 79 | */ 80 | public function getSysStatus() 81 | { 82 | $uname = explode("\n", exec_cli("uname -n"))[0]; 83 | $piduu = explode("\n", exec_cli("ls /lib/systemd/system/uucp.socket"))[0]; 84 | $piduuardop = explode("\n", exec_cli("pgrep -x uuardopd"))[0]; 85 | $pidmodem = explode("\n", exec_cli("pgrep -x VARA.exe"))[0]; 86 | $pidradio = explode("\n", exec_cli("pgrep -x ubitx_controlle"))[0]; 87 | $nodename = explode("\n", exec_cli("cat /etc/uucp/config|grep nodename|cut -f 2 -d \" \""))[0]; 88 | $pidhmp = explode("\n", exec_cli("pgrep -x iwatch"))[0]; 89 | $piddb = explode("\n", exec_cli("pgrep -x mariadbd"))[0]; 90 | $pidpf = explode("\n", exec_cli("pgrep -x master"))[0]; 91 | $pidvnc = explode("\n", exec_cli("pgrep -x Xtigervnc"))[0]; 92 | $wifiessid = explode("\n", exec_cli("cat /etc/hostapd/hostapd.conf | grep ssid | cut -c6-"))[0]; 93 | $wifich= explode("\n", exec_cli("cat /etc/hostapd/hostapd.conf | grep channel| cut -c9-"))[0]; 94 | $ip = explode("\n", exec_cli('/sbin/ifconfig | sed -En \'s/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p\'')); 95 | array_pop($ip); 96 | $disk_free = explode("\n", exec_cli("df / | grep -v Filesystem | awk '{print $4}'"))[0]; 97 | $interfaces= explode("\n", exec_cli('ip r')); 98 | array_pop($interfaces); 99 | $memory = explode(" ", exec_cli("free --mega| grep Mem | awk '{print ($2\" \"$3\" \"$4)}'")); 100 | $phpmemory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB'; 101 | $status = [ 102 | 'status' => $piduu && $piduuardop && $pidmodem && $pidradio && $pidhmp && $piduu && $pidpf, 103 | 'uname' => $uname, 104 | 'nodename' => $nodename, 105 | 'name' => env('HERMES_NAME'), 106 | 'network' => env('HERMES_NETWORK'), 107 | 'domain' => env('HERMES_DOMAIN'), 108 | 'gateway' => env('HERMES_GATEWAY'), 109 | 'ip' => $ip, 110 | 'interfaces' => $interfaces, 111 | 'wifiessid' => $wifiessid?$wifiessid:false, 112 | 'wifich' => $wifich?$wifich:false, 113 | 'interfaces' => $interfaces, 114 | 'piduu' => $piduu?$piduu:false, 115 | 'piduuardop' => $piduuardop?$piduuardop:false, 116 | 'pidmodem' => $pidmodem?$pidmodem:false, 117 | 'pidradio' => $pidradio?$pidradio:false, 118 | 'pidhmp' => $pidhmp?$pidhmp:false, 119 | 'piddb' => $piddb?$piddb:false, 120 | 'pidpf' => $pidpf?$pidpf:false, 121 | 'memtotal' => $memory[0]."MB", 122 | 'memused' => $memory[1]."MB", 123 | 'memfree' => explode("\n", $memory[2])[0]."MB", 124 | 'diskfree' => $disk_free?$disk_free:false, 125 | ]; 126 | return response()->json($status, 200); 127 | } 128 | 129 | /** 130 | * Get sensors 131 | * 132 | * @return Table 133 | */ 134 | public function getSensors() 135 | { 136 | $command = "sensors -ju | jq -cM"; 137 | $output = exec_cli($command); 138 | //$output = str_replace("\r\n","",$output); 139 | $output = @json_decode($output); 140 | return response()->json($output, 200); 141 | } 142 | 143 | 144 | /** 145 | * Get mail use on disk 146 | * 147 | * @return Table 148 | */ 149 | public function getMailDiskUsage() 150 | { 151 | //print($users); 152 | $output = exec_cli("echo btrfs filesystem du -s --human-readable /var/vmail/" . env("HERMES_DOMAIN") . "/* | grep -v Total> /tmp/du.sh"); 153 | if (!$output){ 154 | $output = exec_cli("chmod +x /tmp/du.sh"); 155 | if (!$output){ 156 | $disk_free = explode("\n ", exec_cli("sudo /tmp/du.sh")); 157 | return response()->json($disk_free, 200); 158 | } 159 | } 160 | return response()->json("error",500); 161 | } 162 | 163 | /** 164 | * Get files from $path 165 | * 166 | * @return Table 167 | */ 168 | public function getFiles($path) 169 | { 170 | if (!$path ){ 171 | $command = "ls -la /etc/uucp"; 172 | } 173 | $command = "ls -la " . $path; 174 | $output = exec_cli($command); 175 | $output = explode("\n ", $output); 176 | return $output; 177 | } 178 | 179 | /** 180 | * Get all Stations from uucp 181 | * 182 | * @return stations 183 | */ 184 | public function getSysStations(){ 185 | $command = "egrep -v '^\s*#' /etc/uucp/sys | grep system | cut -f 2 -d \" \""; 186 | $output = exec_cli($command); 187 | $sysnames = explode("\n", $output); 188 | 189 | $command2 = "egrep -v '^\s*#' /etc/uucp/sys | grep alias | cut -f 2 -d \" \""; 190 | $output2 = exec_cli($command2); 191 | $sysnames2 = explode("\n", $output2); 192 | 193 | $sysnameslist=[]; 194 | 195 | for ($i = "0" ; $i < count($sysnames); $i++) { 196 | if(!empty($sysnames[$i])) { 197 | // if (empty ($sysnames2[$i])){ 198 | $sysnameslist[] = [ 199 | 'id' => $i, 200 | 'name' => $sysnames[$i], 201 | 'alias' => $sysnames2[$i], 202 | ]; 203 | } 204 | } 205 | 206 | return response()->json($sysnameslist, 200); 207 | } 208 | 209 | /** 210 | * Get transmission spool 211 | * 212 | * @return Json 213 | */ 214 | public function sysGetSpoolList(){ 215 | $command = 'uustat -a| grep -v uuadm | grep -v sudo | grep -v bash | grep -v "\-C"' ; 216 | $output=exec_cli($command) ; 217 | $output = explode("\n", $output); 218 | $spool=[]; 219 | 220 | for ($i = "0" ; $i < count($output); $i++) { 221 | if(!empty($output[$i])) { 222 | $fields = explode(" ", $output[$i]); 223 | if ( $fields[6] != "uuadm"){ 224 | $count=count($fields); 225 | $emails=array(); 226 | $email_info=array(); 227 | $size= 0; 228 | $type=$fields[6]; 229 | $uuid_host= explode(".", $fields[0])[0]; 230 | $uuid=explode(".", $fields[0])[1]; 231 | 232 | // test if spool is a email 233 | if($type == "crmail"){ 234 | // handle when is a multiple email 235 | if ($count > 11){ 236 | for($j = 7 ; $j < $count-3 ; $j++){ 237 | $emails[]=$fields[$j]; 238 | } 239 | $size = $fields[$count-2]; 240 | } 241 | // handle when is a simple email 242 | else{ 243 | $size = $fields[9]; 244 | $emails[]=$fields[7]; 245 | } 246 | $cfile_path=env('HERMES_UUCP') . '/'. $uuid_host . '/C./C.' . $uuid; 247 | $dfile_id= explode(" ", exec_cli('sudo cat ' . $cfile_path))[1]; 248 | $dfile_path=env('HERMES_UUCP') . '/' . $uuid_host . '/D./' . $dfile_id; 249 | $dfile= exec_cli('sudo zcat ' . $dfile_path . '| head -1'); 250 | $email_info['from']=explode(" ", explode("\n", $dfile)[0])[1]; 251 | $email_info['from_date_week']=explode(" ", explode("\n", $dfile)[0])[3]; 252 | $email_info['from_date_month']=explode(" ", explode("\n", $dfile)[0])[4]; 253 | $email_info['from_date_day']=explode(" ", explode("\n", $dfile)[0])[5]; 254 | $email_info['from_date_year']=explode(" ", explode("\n", $dfile)[0])[7]; 255 | $email_info['from_date_time']=explode(" ", explode("\n", $dfile)[0])[6]; 256 | } 257 | 258 | //not a email 259 | else{ 260 | $size = explode("(",$fields[7])[1]; 261 | $emails = null; 262 | 263 | } 264 | $spool[] = [ 265 | 'uuidhost' => $uuid_host, 266 | 'uuiduucp' => $uuid, 267 | 'dest' => $fields[1], 268 | 'user' => $fields[2], 269 | 'date' => $fields[3], 270 | 'time' => $fields[4], 271 | 'type' => $type == "crmail" ? "Mail" : "HMP", 272 | //'size' => $fields[5] == "Executing" ? $fields[9] : explode("(",$fields[7])[1], 273 | 'size' => intval($size), 274 | 'destpath' => $fields[6] == "crmail" ? null: $fields[10] , 275 | 'emails' => $emails, 276 | 'emailinfo' => $email_info, 277 | ]; 278 | } 279 | } 280 | } 281 | 282 | if (sizeof($spool) >= 1){ 283 | return response()->json($spool, 200); 284 | } 285 | else{ 286 | return response()->json(null, 200); 287 | } 288 | } 289 | 290 | /** 291 | * rejuvenate (route disabled) 292 | * 293 | * @return json message 294 | */ 295 | public function uucpRejuvenateJob($id){ 296 | $command = 'sudo uustat -r ' . $id; 297 | $output=exec_cli($command) or die; 298 | return response($output, 200); 299 | } 300 | 301 | /** 302 | * kill uucp mail jobs with mailkill returning a email 303 | * 304 | * @return json message 305 | */ 306 | public function uucpKillMail($host, $id){ 307 | $command = 'sudo mailkill.sh es gui ' . $host . '.' . $id; 308 | ob_start(); 309 | system($command , $return_var); 310 | $output = ob_get_contents(); 311 | ob_end_clean(); 312 | if ($return_var == 0) { 313 | return response()->json("uucp job killed: " . $host . '.' .$id, 200); 314 | } 315 | else{ 316 | return response()->json("No job found", 404); 317 | } 318 | } 319 | 320 | /** 321 | * kill uucp jobs 322 | * 323 | * @return json message 324 | */ 325 | public function uucpKillJob($host, $id){ 326 | $command = 'sudo uustat -k ' . $host . '.' . $id; 327 | $output=exec_cli($command) or die; 328 | return response()->json("uucp job killed: " . $host . '.' .$id, 200); 329 | } 330 | 331 | /** 332 | * kill all uucp jobs 333 | * 334 | * @return json message 335 | */ 336 | public function uucpKillJobs(){ 337 | $command = 'sudo uustat -Ka '; 338 | $output=exec_cli($command) or die; 339 | return response($output, 200); 340 | } 341 | 342 | /** 343 | * kill uucp common jobs 344 | * 345 | * @return json message 346 | */ 347 | public function uucpCall(){ 348 | $command = 'sudo uucico -r1 ' ; 349 | $output=exec_cli($command); 350 | return response($output, 200); 351 | } 352 | 353 | /** 354 | * system restart 355 | * 356 | * @return json message 357 | */ 358 | public function sysRestart() { 359 | $command = "sudo systemctl stop uuardopd"; 360 | $output0 = exec_cli($command); 361 | 362 | $command = "sudo systemctl stop ardop"; 363 | $output1 = exec_cli($command); 364 | 365 | $command = "sleep 1"; 366 | $output2 = exec_cli($command); 367 | 368 | $command = "sudo systemctl start ardop"; 369 | $output3 = exec_cli($command); 370 | 371 | $command = "sudo systemctl start uuardopd" ; 372 | $output4 = exec_cli($command); 373 | 374 | return response()->json([$output0,$output1,$output2,$output3,$output4],200); 375 | } 376 | 377 | /** 378 | * system reboot 379 | * 380 | * @return json message 381 | */ 382 | public function sysReboot(){ 383 | $command = "sudo reboot"; 384 | $output = exec_cli($command); 385 | return json_encode("rebooted"); 386 | } 387 | 388 | /** 389 | * system shutdown 390 | * 391 | * @return json message 392 | */ 393 | public function sysShutdown(){ 394 | // set led status OFF on cabinet 395 | exec_uc("set_led_status -a OFF"); 396 | sleep(1); 397 | 398 | // linux shutdown 399 | $command = "sudo halt"; 400 | exec_cli($command); 401 | return json_encode("halted"); 402 | } 403 | 404 | /** 405 | * TODO system restore 406 | * 407 | * @return json message 408 | */ 409 | public function sysRestore(){ 410 | $command = "echo test running on php restore"; 411 | $output = exec_cli($command); 412 | return json_encode($output); 413 | } 414 | 415 | /** 416 | * system logs email 417 | * 418 | * @return json maillog 419 | */ 420 | public function sysLogMail(){ 421 | $command = "sudo tail /var/log/mail.log -n 1000| sort -n "; 422 | $output=exec_cli($command); 423 | $output = explode("\n",$output); 424 | ob_clean(); 425 | ob_start(); 426 | 427 | return response()->json($output,200); 428 | } 429 | 430 | /** 431 | * system logs uucp 432 | * 433 | * @return json uucplog 434 | */ 435 | public function sysLogUucp(){ 436 | $command = "sudo uulog -n 1000 | sort -n "; 437 | $output=exec_cli($command); 438 | $output = explode("\n",$output); 439 | 440 | ob_clean(); 441 | ob_start(); 442 | return response()->json($output,200); 443 | } 444 | 445 | /** 446 | * system logs uucp Debug 447 | * 448 | * @return json uucpDebuglog 449 | */ 450 | public function sysDebUucp(){ 451 | $command = "sudo uulog -D -n 1000 | sort -n "; 452 | $output=exec_cli($command); 453 | $output = explode("\n",$output); 454 | ob_clean(); 455 | ob_start(); 456 | return response()->json($output,200); 457 | } 458 | } 459 | -------------------------------------------------------------------------------- /app/Http/Controllers/MessageController.php: -------------------------------------------------------------------------------- 1 | json(Message::all()); 25 | } 26 | 27 | /** 28 | * Get all messages by type 29 | * parameter: 30 | * 31 | * @return Json Messages 32 | */ 33 | public function showAllMessagesByType($type) 34 | { 35 | if($type=='inbox'){ 36 | return response()->json(Message::where('inbox', '=', true)->orderBy('sent_at', 'DESC')->get()); 37 | } 38 | if($type=='draft'){ 39 | return response()->json(Message::where('draft', '=', true)->orderBy('sent_at', 'DESC')->get()); 40 | } 41 | else{ 42 | return response()->json(Message::where('inbox', '!=', true)->where('draft', '!=', true)->orderBy('sent_at', 'DESC')->get()); 43 | } 44 | } 45 | 46 | /** 47 | * Get a message 48 | * parameter: message id 49 | * 50 | * @return Json 51 | */ 52 | public function showOneMessage($id) 53 | { 54 | return response()->json(Message::find($id)); 55 | } 56 | 57 | /** 58 | * SendHMP - Send Hermes Message Pack 59 | * parameter: http request 60 | * 61 | * @return Json 62 | */ 63 | public function sendHMP(Request $request) 64 | { 65 | $request->inbox=false; 66 | $request->orig = explode("\n", exec_cli("cat /etc/uucp/config|grep nodename|cut -f 2 -d \" \""))[0]; 67 | 68 | if($message = Message::create($request->all())){ 69 | if($request->pass && $request->pass!='' && $request->pass!='undefined'){ 70 | $command = 'echo "'. $request->text . '"| gpg -o - -c -t --cipher-algo AES256 --utf8-strings --batch --passphrase "' . $request->pass. '" --yes -'; 71 | $cryptout = ""; 72 | if ($output = exec_cli($command) ){ 73 | $cryptout = $output; // redundant 74 | } 75 | else { 76 | return response()->json(['message' => 'sendHMP: can\'t encrypt the message: ' ], 500); 77 | } 78 | $message->secure=true; 79 | $message->text=bin2hex($cryptout); 80 | $message->save(); 81 | } 82 | 83 | //log 84 | Log::info('creating message ' . $message); 85 | //find the message in database 86 | // Assures to delete the working path 87 | Storage::deleteDirectory('tmp/'.$message->id); 88 | 89 | // Write message file 90 | if (! Storage::disk('local')->put('tmp/' . $message->id . '/hmp.json' , $message)){ 91 | return response()->json(['message' => 'sendHMP Error: can\'t write message file'], 500); 92 | } 93 | 94 | // Has file? 95 | if ($message->fileid && Storage::disk('local')->exists('uploads/'.$message->fileid)) { 96 | // TODO Mantain original files? 97 | if (! Storage::disk('local')->copy('uploads/' . $message->fileid, 'tmp/' . $message->id . '/' .$message->fileid )){ 98 | return response()->json(['message' => 'Hermes send message Error: can\'t move file'], 500); 99 | } 100 | } 101 | 102 | $pathtmp = Storage::disk('local')->path('tmp'); 103 | $command = 'tar cfz ' . $pathtmp . '/' . $message->id . '.hmp -C '. $pathtmp . ' ' . $message->id ; 104 | if ($output = exec_cli($command) ){ 105 | return response()->json(['message' => 'Hermes send message Error: cant move image file' . $output . $command], 500); 106 | } 107 | $origpath = 'tmp/' . $message->id . '.hmp'; 108 | 109 | 110 | // check file size 111 | $hmpsize = Storage::disk('local')->size($origpath); 112 | if ( $hmpsize > env('HERMES_MAX_FILE')){ 113 | $path = Storage::disk('local')->delete($origpath); 114 | return response()->json(['message' => 'HMP error: larger than ' . env('HERMES_MAX_FILE')], 500); 115 | } 116 | 117 | // set new origpath on outbox 118 | $origpath = env('HERMES_OUTBOX') . '/' . $message->id . '.hmp'; 119 | $path = Storage::disk('local')->path($origpath); 120 | 121 | //work path 122 | if (!env('HERMES_OUTBOX')){ 123 | return response()->json(['message' => 'Hermes pack message Error: cant package the file' . $path], 500); 124 | } 125 | 126 | // Clean outbox destination and move the package 127 | if (! Storage::disk('local')->move('tmp/'.$message->id.'.hmp', $origpath)){ 128 | return response()->json(['message' => 'Hermes pack message Error: cant package the file' . $path], 500); 129 | } 130 | //$message = @json_decode(json_encode($messagefile), true); 131 | Storage::disk('local')->deleteDirectory('tmp/'.$message->id); 132 | 133 | 134 | // UUCP -C Copy (default) / -d create dirs 135 | if (Storage::disk('local')->exists($origpath)) { 136 | //send message by uucp 137 | foreach ($message->dest as $dest){ 138 | //check spool size 139 | $command = "uustat -s " . $dest . " -u www-data | egrep -o '(\w+)\sbytes' | awk -F ' ' '{sum+=$1; } END {print sum}'"; 140 | $destspoolsize = exec_cli($command); 141 | $destspoolsize = $hmpsize + intval($destspoolsize); 142 | if ($destspoolsize > env('HERMES_MAX_SPOOL')){ 143 | $path = Storage::disk('local')->delete($origpath); 144 | return response()->json(['message' => 'HMP error: spool larger than ' . env('HERMES_MAX_SPOOL') .' bytes ' ], 500); 145 | } 146 | 147 | $command = 'uucp -r -j -C -d \'' . $path . '\' \'' . $dest . '!~/' . $message->orig . '_' . $message->id . '.hmp\''; 148 | if(!$output = exec_cli_no($command)){ 149 | return response()->json(['message' => 'Hermes sendMessage - Error on uucp: ' . $output . ' - ' .$command], 500); 150 | } 151 | } 152 | //setting no draft 153 | if (! $message->update([ 'draft' => false])){ 154 | return response()->json(['message' => 'Hermes sendMessage - cant update no draft: ' . $output ], 500); 155 | } 156 | //delete hmp file 157 | if ( Storage::disk('local')->delete($origpath)); 158 | 159 | Log::info('sent message ' . $message->id); 160 | } 161 | else{ 162 | return response()->json(['message' => 'Hermes send message Error: Cant find '.$path], 500); 163 | } 164 | } 165 | else{ 166 | return response()->json(['message' => 'Hermes pack message Error: can\'t create message in DB'], 500); 167 | } 168 | 169 | return response()->json(['message' => 'Hermes sendMessage: DONE', 'content' => $message], 200); 170 | } 171 | 172 | 173 | /** 174 | * updateMessage - update Hermes Message Pack (DEPRECATED) 175 | * parameter: id and http request 176 | * 177 | * @return Json 178 | */ 179 | public function updateMessage($id, Request $request) 180 | { 181 | if($message = Message::findOrFail($id)){ 182 | $message->update($request->all()); 183 | Log::info('update message ' . $id); 184 | return response()->json($user, 200); 185 | } 186 | else{ 187 | Log::warning('update message cant find ' . $id); 188 | return response()->json(['message' => 'cant find ' . $id], 404); 189 | } 190 | } 191 | 192 | /** 193 | * deleteMessage - deleteMessage 194 | * parameter: message id 195 | * @return Json 196 | */ 197 | public function deleteMessage($id) 198 | { 199 | $message = Message::findOrFail($id); 200 | Message::findOrFail($id)->delete(); 201 | if ( $message->fileid){ 202 | if ($message->inbox){ 203 | Storage::disk('local')->delete('downloads/' . $message->fileid); 204 | } 205 | else{ 206 | Storage::disk('local')->delete('uploads/' . $message->fileid); 207 | 208 | } 209 | } 210 | Log::info('delete message ' . $id); 211 | return response()->json(['message' => 'Delete sucessfully message: ' . $id], 200); 212 | } 213 | 214 | /** 215 | * unpackInboxMessage - Unpack Hermes Message Pack 216 | * parameter: id and http request 217 | * 218 | * @return Json 219 | */ 220 | public function unpackInboxMessage($arg){ 221 | $arga = explode('_', $arg); 222 | $orig = $arga[0]; 223 | $id = $arga[1]; 224 | $id = explode('.', $id)[0]; 225 | 226 | $message=''; 227 | // Test for tmp dir, if doesnt exist, creates it 228 | if (! Storage::disk('local')->exists('inbox/tmp')){ 229 | if(!Storage::disk('local')->makeDirectory('tmp')){ 230 | return response()->json(['message' => 'Hermes unpack inbox message Error: can\'t find or create tmp dir'], 500); 231 | } 232 | } 233 | // Test for HMP file and unpack it 234 | if (Storage::disk('local')->exists('inbox/'. $orig . '_' . $id . '.hmp')){ 235 | // Get path, unpack into tmp and read message data 236 | $path = Storage::disk('local')->path(''); 237 | $command = 'tar xvfz ' . $path . 'inbox/' . $orig .'_' . $id . '.hmp' . ' -C ' . $path . 'tmp/' ; 238 | $output = exec_cli($command); 239 | $files[] = explode(' ', $output); 240 | 241 | // Test for HMP: hermes message package, create record on messages database 242 | if (Storage::disk('local')->exists('tmp/'.$id.'/hmp.json')){ 243 | $messagefile = json_decode(Storage::disk('local')->get('tmp/'. $id . '/hmp.json')); 244 | $message = @json_decode(json_encode($messagefile), true); 245 | // force reset id to get the next from db 246 | $message['id'] = null; 247 | // force inbox flag 248 | $message['inbox'] = true; 249 | } 250 | else { 251 | return response()->json(['message' => 'Hermes unpack inbox message Error: cant find json file from unpacked message'], 500); 252 | } 253 | 254 | //create message on database, delete tar and hmp 255 | if(!$message = Message::create($message)){ 256 | return response()->json(['message' => 'Hermes unpack inbox message Error: cant create message on db'], 500); 257 | } 258 | 259 | // Move attached files 260 | // test for field file and fileid in message 261 | if($message['file'] && $message['fileid']) 262 | { 263 | // test if file exists 264 | if (Storage::disk('local')->exists('tmp/'.$id.'/' . $message['fileid'])){ 265 | // Test and create download folder if it doesn't exists 266 | if (! Storage::disk('local')->exists('downloads')){ 267 | if(!Storage::disk('local')->makeDirectory('downloads')){ 268 | return response()->json(['message' => 'Hermes unpack inbox message Error: can\'t find or create downloads dir'], 500); 269 | } 270 | } 271 | // movefile 272 | if (! Storage::disk('local')->move('tmp/' . $id .'/' . $message['fileid'] , 'downloads/' . $message['fileid'] )){ 273 | return response()->json(['message' => 'Hermes unpack inbox message Error: can\'t move imagefile'], 500); 274 | } 275 | // TODO move audio and other files 276 | } 277 | } 278 | 279 | if(env('MAIL_FROM_NAME')){ 280 | 281 | $data = array('name'=>$message['name'], 282 | 'text'=>$message['text'], 283 | 'file'=>$message['file'], 284 | 'fileid'=>$message['fileid'], 285 | 'mimetype'=>$message['mimetype'], 286 | 'sent_at'=>$message['sent_at'], 287 | 'orig'=>$message['orig'], 288 | 'dest'=>$message['dest'] 289 | ); 290 | 291 | // $data = array('dest'=>$message['dest']); 292 | // $data = array('orig'=>$message['orig']); 293 | // $data = array('sent_at'=>$message['sent_at']); 294 | 295 | Mail::send('mail', $data, function($message) { 296 | // $subject = 'Hermes HMP: ' . $message->subject; 297 | $message->to(env('HERMES_FWD_EMAIL'))->subject('HERMES Public message '); 298 | // $message->from('selva@snamservices.com','Selvakumar'); 299 | }); 300 | 301 | } 302 | 303 | if (Storage::disk('local')->exists('tmp/'.$id)){ 304 | if (!Storage::disk('local')->deleteDirectory('tmp/' . $id)){ 305 | return response()->json(['message' => 'Hermes unpack inbox message Error: can\'t delete tmp dir'], 500); 306 | } 307 | // $fullpath = Storage::disk('local')->path('inbox/'. $orig . '_' . $message['id'] . '.hmp'); 308 | $fullpath = Storage::disk('local')->path('inbox/'. $arg); 309 | $command = 'sudo rm -f ' . $fullpath; 310 | if (! exec_cli_no($command)){ 311 | return response()->json(['message' => 'Hermes unpack inbox message Error: can\'t delete orig file'], 500); 312 | } 313 | } 314 | else{ 315 | return response()->json(['message' => 'Hermes unpack inbox message Error: can\'t create message on database'], 500); 316 | } 317 | } 318 | else { 319 | return response()->json(['message' => 'Hermes unpack inbox message Error: can\'t find HMP'], 500); 320 | } 321 | Log::info('API unpack '. $id . ' - ' . $message . ' from ' . $orig ); 322 | 323 | return response()->json(['message' => $message], 200); 324 | } 325 | 326 | /** 327 | * showAllInboxMessages 328 | * 329 | * @return Json 330 | */ 331 | public function showAllInboxMessages() 332 | { 333 | $files = \Storage::allFiles('inbox'); 334 | $file = []; 335 | 336 | /*$filtered_files = array_filter($files, function($str){ 337 | return strpos($str, 'hmp') === 0; 338 | });*/ 339 | 340 | $files_out = []; 341 | for ($i = '0' ; $i < count($files); $i++) { 342 | $file = explode('inbox/', $files[$i]); 343 | 344 | if(!empty($files[$i])) { 345 | $files_out[] = $file[1]; 346 | } 347 | 348 | } 349 | //var_dump($files_out); 350 | return response()->json($files_out); 351 | } 352 | 353 | /** 354 | * showOneInboxMessage 355 | * parameter: message id 356 | * @return Json 357 | */ 358 | public function showOneInboxMessage($id) 359 | { 360 | $file = \Storage::get('inbox/' . $id); 361 | $output = explode('}', $file)[0]; 362 | $output = $output . '}'; 363 | $output = json_decode($output); 364 | return response()->json($output); 365 | } 366 | 367 | /** 368 | * parameter: message id 369 | * @return Json 370 | */ 371 | public function hideInboxMessage($id) 372 | { 373 | \Storage::move('inbox/' . $id, 'inbox/.' . $id); 374 | log::info('hide message ' . $id); 375 | return response()->json(['hide messag ' . $id . 'Sucessfully'], 200); 376 | } 377 | 378 | /** 379 | * unhideInboxMessage 380 | * parameter: message id 381 | * 382 | * @return Json 383 | */ 384 | public function unhideInboxMessage($id) 385 | { 386 | \Storage::move('inbox/.' . $id, 'inbox/' . $id); 387 | return response()->json(['unhide' . $id . 'Sucessfully'], 200); 388 | } 389 | 390 | /** 391 | * unCrypt text message 392 | * parameter: message id, $request->pass 393 | * @return Json 394 | */ 395 | public function unCrypt($id, Request $request){ 396 | if ($request->pass && $request->pass != '') { 397 | if ($message = Message::find($id)){ 398 | if ($message['secure'] ){ 399 | $crypt = hex2bin($message['text']); 400 | if ( Storage::disk('local')->put('tmp/' . $message->id . '-uncrypt' , $crypt)){ 401 | $path = Storage::disk('local')->path('tmp') . '/' . $message->id . '-uncrypt'; 402 | $command = 'gpg -d --batch --passphrase "' . $request->pass . '" --decrypt ' . $path ; 403 | $output = exec_cli($command); 404 | 405 | Log::info('message unCrypt '. $id . ' - ' . $output ); 406 | return response()->json(['text' => $output], 200); 407 | } 408 | } 409 | else{ 410 | Log::warning('message unCrypt message is not secure '. $id . ' - ' . $output ); 411 | return response()->json(['message' => 'HMP uncrypt error: message is not secured'], 500); 412 | } 413 | 414 | } 415 | else{ 416 | return response()->json(['message' => 'HMP uncrypt error: cant find message'], 500); 417 | } 418 | } 419 | else{ 420 | return response()->json(['message' => 'HMP uncrypt error: form pass is required'], 500); 421 | } 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /app/Http/Controllers/RadioController.php: -------------------------------------------------------------------------------- 1 | $radio_frequency, 76 | 'mode' => $radio_mode, 77 | 'led' => $radio_led, 78 | 'bfo' => $radio_bfo, 79 | 'txrx' => $radio_txrx, 80 | 'tx' => $radio_tx, 81 | 'rx' => $radio_rx, 82 | 'mastercal' => $radio_mastercal, 83 | 'protection' => $radio_protection, 84 | 'refthreshold' => $radio_ref_threshold, 85 | 'refthresholdv'=> $radio_ref_thresholdv, 86 | 'connection' => $radio_connection, 87 | 'serial' => $radio_serial, 88 | 'testtone' => $radio_test_tone 89 | ]; 90 | return response()->json($status, 200); 91 | } 92 | 93 | /** 94 | * Get ptt / swr 95 | * 96 | * @return Json 97 | */ 98 | public function getRadioPowerStatus() 99 | { 100 | $radio_txrx= explode("\n", exec_uc("get_txrx_status"))[0]; 101 | 102 | $radio_rx=true; 103 | $radio_tx=false; 104 | $radio_ref=0; 105 | $radio_ref_volts=0; 106 | $radio_ref_watts=0; 107 | $radio_fwd=0; 108 | $radio_fwd_watts=0; 109 | $radio_fwd_volts=0; 110 | $radio_swr=0; 111 | 112 | if($radio_txrx== "INTX" || !$radio_txrx){ 113 | $radio_tx =true; 114 | $radio_rx =false; 115 | $radio_fwd = explode("\n", exec_uc("get_fwd"))[0]; 116 | 117 | if(isset($radio_fwd)){ 118 | $radio_fwd_volts = adc2volts($radio_fwd); 119 | $radio_fwd_watts = fwd2watts($radio_fwd); 120 | } 121 | else{ 122 | $radio_fwd_watts = 0; 123 | } 124 | $radio_ref = explode("\n", exec_uc("get_ref"))[0]; 125 | if (isset($radio_ref)){ 126 | $radio_ref_volts = adc2volts($radio_ref); 127 | $radio_ref_watts = ref2watts($radio_ref); 128 | } 129 | else{ 130 | $radio_ref_volts = 0; 131 | $radio_ref = 0; 132 | } 133 | $radio_swr = swr($radio_ref, $radio_fwd); 134 | } 135 | 136 | $radio_led= explode("\n", exec_uc("get_led_status"))[0]; 137 | if ($radio_led== "LED_ON"){ 138 | $radio_led=true; 139 | } 140 | else if($radio_led == "LED_OFF" || !$radio_led){ 141 | $radio_led=false; 142 | } 143 | 144 | $radio_protection= explode("\n", exec_uc("get_protection_status"))[0]; 145 | if ($radio_protection == "PROTECTION_ON"){ 146 | $radio_protection=true; 147 | } 148 | else if($radio_protection == "PROTECTION_OFF" || !$radio_protection){ 149 | $radio_protection = false; 150 | } 151 | 152 | $radio_connection= explode("\n", exec_uc("get_connected_status"))[0]; 153 | if ($radio_connection== "LED_ON"){ 154 | $radio_connection=true; 155 | } 156 | else if($radio_connection == "LED_OFF" || !$radio_connection){ 157 | $radio_connection = false; 158 | } 159 | 160 | $status = [ 161 | // 'txrx' => $radio_txrx, 162 | 'tx' => $radio_tx, 163 | 'rx' => $radio_rx, 164 | 'led' => $radio_led, 165 | 'fwd_raw' => $radio_fwd, 166 | 'fwd_volts' => $radio_fwd_volts, 167 | 'fwd_watts' => $radio_fwd_watts, 168 | 'swr' => $radio_swr, 169 | 'ref_raw' => $radio_ref, 170 | 'ref_volts' => $radio_ref_volts, 171 | 'ref_watts' => $radio_ref_watts, 172 | 'protection' => $radio_protection, 173 | 'connection' => $radio_connection, 174 | ]; 175 | return response()->json($status, 200); 176 | } 177 | 178 | /** 179 | * 180 | * Get TX RX Statustxrx_status 181 | * 182 | * @return Json 183 | * 184 | */ 185 | public function getRadioTXRXStatus() 186 | { 187 | $radio_frequency= explode("\n", exec_uc("get_txrx_status"))[0]; 188 | return response($radio_frequency, 200); 189 | } 190 | 191 | /** 192 | * 193 | * Set PTT 194 | * 195 | * @return Json 196 | * 197 | */ 198 | public function setRadioPtt($status) 199 | { 200 | $command=""; 201 | if ($status == "ON"){ 202 | $command = "ptt_on"; 203 | } 204 | elseif ($status == "OFF"){ 205 | $command = "ptt_off"; 206 | } 207 | else{ 208 | $command = "ptt_off"; 209 | return response()->json("setRadioPTTon: invalid parameter: " . $status, 500); 210 | } 211 | 212 | $output = exec_uc($command); 213 | $output = explode("\n", $output)[0]; 214 | if ($output == "OK"){ 215 | return response()->json("setRadioPTT: " . $status . " - " . $output, 200); 216 | } 217 | else{ 218 | return response()->json(["message"=>"setRadioPTT: Error - " . $output], 500); 219 | } 220 | } 221 | 222 | /** 223 | * 224 | * Set radio test Tone 225 | * 226 | * @return Json 227 | * 228 | */ 229 | public function setRadioTone($par) 230 | { 231 | system("sudo killall ffplay"); 232 | 233 | switch ($par) { 234 | case "600": 235 | $command = 'su hermes -c "ffplay -f lavfi -i \"sine=frequency=600\" -nodisp" &'; 236 | $output = system("$command"); 237 | break; 238 | case "1500": 239 | $command = 'su hermes -c "ffplay -f lavfi -i \"sine=frequency=1500\" -nodisp" &'; 240 | $output = system("$command"); 241 | break; 242 | case "3000": 243 | $command = 'su hermes -c "ffplay -f lavfi -i \"sine=frequency=300\" -nodisp" &'; 244 | $output = system("$command"); 245 | $command = 'su hermes -c "ffplay -f lavfi -i \"sine=frequency=2700\" -nodisp" &'; 246 | $output = system("$command"); 247 | break; 248 | default: 249 | $command = "sudo killall ffplay"; 250 | $output = system("$command"); 251 | break; 252 | } 253 | $output = explode("\n", $output)[0]; 254 | if ( !$output) { 255 | return response()->json($par, 200); 256 | } 257 | else { 258 | return response()->json(["message"=>"setRadioTone: Error - " . $output], 500); 259 | } 260 | } 261 | 262 | /** 263 | * 264 | * Get Radio Main Frequency Oscilator 265 | * 266 | * @return Json 267 | */ 268 | public function getRadioFreq() 269 | { 270 | $radio_frequency= explode("\n", exec_uc("get_frequency"))[0]; 271 | return response()->json($radio_frequency, 200); 272 | } 273 | 274 | /** 275 | * Set Radio Main Frequency Oscilator 276 | * 277 | * @return Json 278 | */ 279 | public function setRadioFreq(int $freq) 280 | { 281 | $command = explode("\n", exec_uc("set_frequency -a " . $freq))[0]; 282 | if ($command == "OK"){ 283 | $radio_frequency = explode("\n", exec_uc("get_frequency"))[0]; 284 | return response()->json($radio_frequency, 200); 285 | } 286 | else { 287 | return response()->json(['message' => 'setRadioFreq error: ' . $command], 500); 288 | 289 | } 290 | } 291 | 292 | /** 293 | * Get Radio Mode 294 | * 295 | * @return Json 296 | */ 297 | public function getRadioMode() 298 | { 299 | $radio_mode= explode("\n", exec_uc("get_mode"))[0]; 300 | return response()->json($radio_mode, 200); 301 | } 302 | 303 | /** 304 | * Set Radio Mode 305 | * USB OR LSB 306 | * 307 | * @return Json 308 | */ 309 | public function setRadioMode($mode) 310 | { 311 | $radio_mode = ""; 312 | if($mode == "USB"){ 313 | $command = explode("\n", exec_uc("set_mode -a USB"))[0]; 314 | } 315 | elseif( $mode == "LSB"){ 316 | $command= explode("\n", exec_uc("set_mode -a LSB"))[0]; 317 | } 318 | else{ 319 | return response()->json(['message' => 'setRadioMode invalid error: is not USB or LSB' . $mode], 500); 320 | } 321 | 322 | if ($command== "OK"){ 323 | $radio_mode= explode("\n", exec_uc("get_mode"))[0]; 324 | return response()->json($radio_mode, 200); 325 | } 326 | else{ 327 | return response()->json(['message' => 'setRadioMode error: ' . $radio_mode ], 500); 328 | 329 | } 330 | } 331 | 332 | /** 333 | * Get Radio Beat Frequency Oscilator 334 | * 335 | * @return Json 336 | */ 337 | public function getRadioBfo() 338 | { 339 | $bfo= explode("\n", exec_uc("get_bfo"))[0]; 340 | return response()->json($bfo, 200); 341 | } 342 | 343 | /** 344 | * Set Radio Beat Frequency Oscilator 345 | * 346 | * @return Json 347 | */ 348 | public function setRadioBfo($freq) 349 | { 350 | $command = explode("\n", exec_uc("set_bfo -a " . $freq))[0]; 351 | if ($command == "OK"){ 352 | $radio_bfo = explode("\n", exec_uc("get_bfo"))[0]; 353 | return response($radio_bfo , 200); 354 | } 355 | else { 356 | return response()->json(['message' => 'setRadioBfo error: ' . $command], 500); 357 | } 358 | } 359 | 360 | /** 361 | * Get Radio Forward 362 | * 363 | * @return Json 364 | */ 365 | public function getRadioFwd() 366 | { 367 | $bfo= explode("\n", exec_uc("get_fwd"))[0]; 368 | return response()->json($bfo, 200); 369 | } 370 | 371 | /** 372 | * Get Radio Ref 373 | * 374 | * @return Json 375 | */ 376 | public function getRadioRef() 377 | { 378 | $radio_ref = explode("\n", exec_uc("get_ref"))[0]; 379 | return response()->json($radio_ref, 200); 380 | } 381 | 382 | /** 383 | * Get Radio TXRX 384 | * 385 | * @return Json 386 | */ 387 | public function getRadioTxrx() 388 | { 389 | $radio_txrx = explode("\n", exec_uc("get_txrx"))[0]; 390 | return response()->json( $radio_txrx, 200); 391 | } 392 | 393 | /** 394 | * Get Radio mastercal 395 | * 396 | * @return Json 397 | */ 398 | public function getRadioMasterCal() 399 | { 400 | $radio_mastercal= explode("\n", exec_uc("get_mastercal"))[0]; 401 | return response()->json($radio_mastercal, 200); 402 | } 403 | 404 | /** 405 | * Set Radio Mastercal 406 | * 407 | * @return Json 408 | */ 409 | public function setRadioMasterCal($freq) 410 | { 411 | $command = explode("\n", exec_uc("set_mastercal -a " . $freq))[0]; 412 | if ($command == "OK"){ 413 | $radio_fwd= explode("\n", exec_uc("get_mastercal"))[0]; 414 | return response()->json($radio_fwd, 200); 415 | } 416 | else { 417 | return response()->json(['message' => 'setRadioMasterCal error: ' . $command], 500); 418 | 419 | } 420 | } 421 | 422 | /** 423 | * Get Radio protection status 424 | * 425 | * @return Json bool 426 | */ 427 | public function getRadioProtection() 428 | { 429 | $radio_protection = explode("\n", exec_uc("get_protection_status"))[0]; 430 | if ($radio_protection == "PROTECTION_OFF"){ 431 | return response()->json( false, 200); 432 | } 433 | else if ($radio_protection == "PROTECTION_ON"){ 434 | return response()->json( true, 200); 435 | } 436 | else { 437 | return response()->json(['message' => 'setRadioMasterCal error: ' ], 500); 438 | } 439 | } 440 | 441 | /** 442 | * Set Radio LED Status 443 | * 444 | * @return Json 445 | */ 446 | public function setRadioLedStatus($status) 447 | { 448 | $par = ''; 449 | if ($status == "ON"){ 450 | $par = "set_led_status -a ON"; 451 | } 452 | elseif ($status == "OFF"){ 453 | $par = "set_led_status -a OFF"; 454 | } 455 | else{ 456 | return response()->json(['message' => 'setRadioLedStatus fail' ], 500); 457 | } 458 | 459 | $command = explode("\n", exec_uc($par))[0]; 460 | if ($command == "OK"){ 461 | $radio_led= explode("\n", exec_uc("get_led_status"))[0]; 462 | 463 | if ($radio_led == "LED_ON"){ 464 | return response()->json(true, 200); 465 | } 466 | elseif($radio_led == "LED_OFF"){ 467 | return response()->json(false, 200); 468 | } 469 | else { 470 | return response()->json(['message' => 'setRadioBfo return error: ' . $command], 500); 471 | 472 | } 473 | } 474 | else { 475 | return response()->json(['message' => 'setRadioBfo error: ' . $command], 500); 476 | } 477 | } 478 | 479 | /** 480 | * Get Radio LED Status 481 | * 482 | * @return Json 483 | */ 484 | public function getRadioLedStatus() 485 | { 486 | $radio_led= explode("\n", exec_uc("get_led_status"))[0]; 487 | if($radio_led == "LED_ON"){ 488 | return response( true, 200); 489 | } 490 | elseif($radio_led == "LED_OFF"){ 491 | return response( false, 200); 492 | } 493 | else{ 494 | return response()->json(['message' => 'getRadioLetSTatus fail' . $radio_led], 500); 495 | } 496 | } 497 | 498 | /** 499 | * Get Radio Connection Status 500 | * 501 | * @return Json 502 | */ 503 | public function getRadioConnectionStatus() 504 | { 505 | $radio_connection= explode("\n", exec_uc("get_connected_status"))[0]; 506 | if($radio_connection == "LED_ON"){ 507 | return response( true, 200); 508 | } 509 | elseif($radio_connection == "LED_OFF"){ 510 | return response( false, 200); 511 | } 512 | else{ 513 | return response()->json(['message' => 'getRadioConnectionStatus fail' . $radio_connection], 500); 514 | } 515 | 516 | } 517 | 518 | /** 519 | * Set Radio Connection Status 520 | * 521 | * @return Json 522 | */ 523 | public function setRadioConnectionStatus($status) 524 | { 525 | $par = ''; 526 | if ($status == "ON"){ 527 | $par = "set_connected_status -a ON"; 528 | } 529 | elseif ($status == "OFF"){ 530 | $par = "set_connected_status -a OFF"; 531 | } 532 | else{ 533 | return response()->json(['message' => 'setRadioConnectionStatus fail: ' . $status], 500); 534 | } 535 | 536 | $command = explode("\n", exec_uc($par))[0]; 537 | 538 | if ($command == "OK"){ 539 | $radio_connection= explode("\n", exec_uc("get_connected_status"))[0]; 540 | if($radio_connection== "LED_ON"){ 541 | return response( true, 200); 542 | } 543 | elseif($radio_connection== "LED_OFF"){ 544 | return response( false, 200); 545 | } 546 | else{ 547 | return response()->json(['message' => 'getRadioConnectionStatus fail' . $radio_connection], 500); 548 | } 549 | } 550 | else { 551 | return response()->json(['message' => 'setRadioBfo error: ' . $command], 500); 552 | } 553 | } 554 | 555 | /** 556 | * Get Radio serial 557 | * 558 | * @return Json 559 | */ 560 | public function getRadioSerial() 561 | { 562 | $radio_serial = explode("\n", exec_uc("get_serial"))[0]; 563 | if($radio_serial != "ERROR"){ 564 | return response()->json(true, 200); 565 | } 566 | else{ 567 | return response()->json(['message' => 'getRadioSerial fail: ' . $radio_serial], 500); 568 | } 569 | } 570 | 571 | /** 572 | * Get Radio reflected threshold 573 | * 574 | * @return Json 575 | */ 576 | public function getRadioRefThreshold() 577 | { 578 | $radio_ref_threshold = explode("\n", exec_uc("get_ref_threshold"))[0]; 579 | if($radio_ref_threshold != "ERROR"){ 580 | return response()->json($radio_ref_threshold, 200); 581 | } 582 | else{ 583 | return response()->json(['message' => 'getRadioRefThreshold fail: ' . $radio_ref_threshold], 500); 584 | } 585 | } 586 | 587 | /** 588 | * Set Radio Reflected threshold 589 | * 590 | * @return Json 591 | */ 592 | public function setRadioRefThreshold($value) 593 | { 594 | if ($value >= 0 && $value <= 1023){ 595 | $par = "set_ref_threshold -a " . $value; 596 | $radio_ref_threshold = explode("\n", exec_uc($par))[0]; 597 | if($radio_ref_threshold == "OK"){ 598 | return response($value, 200); 599 | } 600 | else{ 601 | return response()->json(['message' => 'setRadioRefThreshold fail: ' . $radio_ref_threshold], 500); 602 | } 603 | } 604 | else { 605 | return response()->json(['message' => 'setRadioRefThreshold out of limit - 0...1023: '. $value] , 500); 606 | } 607 | } 608 | 609 | /** 610 | * Set Radio Reflected threshold in volts 611 | * 612 | * @return Json 613 | */ 614 | public function setRadioRefThresholdV($value) 615 | { 616 | if ($value >= 0 && $value <= 5){ 617 | $ratio = 5/1023; 618 | $vvalue = ceil($value / $ratio); 619 | $par = "set_ref_threshold -a " . $vvalue; 620 | $radio_ref_threshold = explode("\n", exec_uc($par))[0]; 621 | if($radio_ref_threshold == "OK"){ 622 | return response($value, 200); 623 | } 624 | else{ 625 | return response()->json(['message' => 'setRadioRefThresholdV fail: ' . $value], 500); 626 | } 627 | } 628 | else { 629 | return response()->json(['message' => 'setRadioRefThresholdV out of limit - 0...5: '. $value] , 500); 630 | } 631 | } 632 | 633 | /** 634 | * reset radio protection 635 | * 636 | * @return Json 637 | */ 638 | public function resetRadioProtection() 639 | { 640 | $radio_prot = explode("\n", exec_uc("reset_protection"))[0]; 641 | if($radio_prot == "OK"){ 642 | return response( true, 200); 643 | } 644 | else{ 645 | return response()->json(['message' => 'resetRadioProtection fail: ' . $radio_prot], 500); 646 | } 647 | } 648 | 649 | /** 650 | * Set radio defaults 651 | * 652 | * @return Json 653 | */ 654 | public function setRadioDefaults() 655 | { 656 | $output = explode("\n", exec_uc("set_radio_defaults"))[0]; 657 | if($output == "OK"){ 658 | return response( true, 200); 659 | } 660 | else{ 661 | return response()->json(['message' => 'setRadioDefaults fail: ' . $output], 500); 662 | } 663 | } 664 | 665 | /** 666 | * restore radio defaults 667 | * 668 | * @return Json 669 | */ 670 | public function restoreRadioDefaults() 671 | { 672 | $output = explode("\n", exec_uc("restore_radio_defaults"))[0]; 673 | if($output == "OK"){ 674 | return response( true, 200); 675 | } 676 | else{ 677 | return response()->json(['message' => 'restoreRadioDefaults fail: ' . $output], 500); 678 | } 679 | } 680 | 681 | } 682 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------