QuecManger 1.0.0

Release Notes:

Enhanced Web App Architecture:

- Optimized the structure for better scalability and maintainability.

- Refined Data Fetching Logic:
Improved the efficiency and reliability of data retrieval processes.

- Optimized AT Terminal: Enhanced functionality for smoother interaction with AT commands.

- Revamped UI/UX Design: Streamlined user interface and experience for improved accessibility and usability.

New Features:

- MTU Settings: Added customizable Maximum Transmission Unit (MTU) settings.

- APN and IMEI Profiles: Introduced the ability to configure APN and IMEI profiles for better device management.

- Persistent Cell Locking: Added native support for persistent cell locking, ensuring consistent network connections.

- QuecWatch: Connection monitoring with auto reconnect and reboot settable

Co-Authored-By: Russel Yasol <73575327+dr-dolomite@users.noreply.github.com>
This commit is contained in:
Cameron Thompson
2024-12-11 23:11:41 -05:00
parent 46f8e1af8b
commit bb4d75f560
271 changed files with 1791 additions and 108040 deletions

View File

@@ -0,0 +1 @@
/etc/quecManager.conf

View File

@@ -1,6 +1,7 @@
Package: sdxpinn-quecmanager
Version: 0.0.3
Version: 1.0.0
Architecture: aarch64_cortex-a53
Maintainer: Russel Yasol dr-dolomite@github.com Cameron Thompson iamromulan@github.com
Description: A custom web UI desgined to run alongside luci for Quectel RM55x modems
Depends: libc sdxpinn-mount-fix atinout
Conflicts: sdxpinn-quecmanager-beta

View File

@@ -1,6 +1,6 @@
#!/bin/ash
mv /www/index.html /www/index.html.old
mv /www/login.html /www/index.html
cp /www/login.html /www/index.html
exit 0

View File

@@ -0,0 +1,4 @@
AT_port = dev/smd11
AT_port_custom = dev/smd7
data_refresh_rate = 5000
# end of config (don't remove this line)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7409],{66325:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_not-found/page",function(){return n(89094)}])},89094:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return s}}),n(88806);let i=n(20881);n(64149);let o={fontFamily:'system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"',height:"100vh",textAlign:"center",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},l={display:"inline-block"},r={display:"inline-block",margin:"0 20px 0 0",padding:"0 23px 0 0",fontSize:24,fontWeight:500,verticalAlign:"top",lineHeight:"49px"},d={fontSize:14,fontWeight:400,lineHeight:"49px",margin:0};function s(){return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)("title",{children:"404: This page could not be found."}),(0,i.jsx)("div",{style:o,children:(0,i.jsxs)("div",{children:[(0,i.jsx)("style",{dangerouslySetInnerHTML:{__html:"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}),(0,i.jsx)("h1",{className:"next-error-h1",style:r,children:"404"}),(0,i.jsx)("div",{style:l,children:(0,i.jsx)("h2",{style:d,children:"This page could not be found."})})]})})]})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}},function(e){e.O(0,[8985,5330,1744],function(){return e(e.s=66325)}),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1060],{89460:function(t,e,a){Promise.resolve().then(a.bind(a,27442))},27442:function(t,e,a){"use strict";a.r(e);var s=a(20881);a(64149);var n=a(27525),d=a(26509);e.default=t=>{let{children:e}=t,a=(0,n.usePathname)();return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("div",{className:"mx-auto grid w-full max-w-6xl gap-2",children:(0,s.jsx)("h1",{className:"text-3xl font-semibold",children:"Advanced Settings"})}),(0,s.jsxs)("div",{className:"mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]",children:[(0,s.jsxs)("nav",{className:"grid gap-4 text-sm text-muted-foreground","x-chunk":"dashboard-04-chunk-0",children:[(0,s.jsx)(d.default,{href:"/dashboard/advanced-settings/connectivity",className:"".concat("/dashboard/advanced-settings/connectivity/"===a?"font-semibold text-primary":"text-sm"),children:"Connectivity"}),(0,s.jsx)(d.default,{href:"/dashboard/advanced-settings/ttl-settings",className:"".concat("/dashboard/advanced-settings/ttl-settings/"===a?"font-semibold text-primary":"text-sm"),children:"TTL Settings"}),(0,s.jsx)(d.default,{href:"/dashboard/advanced-settings/mtu",className:"".concat("/dashboard/advanced-settings/mtu/"===a?"font-semibold text-primary":"text-sm"),children:"MTU Settings"}),(0,s.jsx)(d.default,{href:"/dashboard/advanced-settings/at-terminal",className:"".concat("/dashboard/advanced-settings/at-terminal/"===a?"font-semibold text-primary":"text-sm"),children:"AT Terminal"})]}),e]})]})}},27525:function(t,e,a){"use strict";var s=a(39886);a.o(s,"usePathname")&&a.d(e,{usePathname:function(){return s.usePathname}}),a.o(s,"useRouter")&&a.d(e,{useRouter:function(){return s.useRouter}})}},function(t){t.O(0,[6509,8985,5330,1744],function(){return t(t.s=89460)}),_N_E=t.O()}]);

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1159],{37946:function(e,s,t){Promise.resolve().then(t.bind(t,78700))},78700:function(e,s,t){"use strict";t.r(s);var a=t(20881);t(64149);var l=t(27525),n=t(26509);s.default=e=>{let{children:s}=e,t=(0,l.usePathname)();return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"mx-auto grid w-full max-w-6xl gap-2",children:(0,a.jsx)("h1",{className:"text-3xl font-semibold",children:"Cellular Settings"})}),(0,a.jsxs)("div",{className:"mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]",children:[(0,a.jsxs)("nav",{className:"grid gap-4 text-sm text-muted-foreground","x-chunk":"dashboard-04-chunk-0",children:[(0,a.jsx)(n.default,{href:"/dashboard/cell-settings/basic-settings",className:"".concat("/dashboard/cell-settings/basic-settings/"===t?"font-semibold text-primary":"text-sm"),children:"Basic Settings"}),(0,a.jsx)(n.default,{href:"/dashboard/cell-settings/band-locking",className:"".concat("/dashboard/cell-settings/band-locking/"===t?"font-semibold text-primary":"text-sm"),children:"Band Locking"}),(0,a.jsx)(n.default,{href:"/dashboard/cell-settings/cell-locking",className:"".concat("/dashboard/cell-settings/cell-locking/"===t?"font-semibold text-primary":"text-sm"),children:"Cellular Locking"}),(0,a.jsx)(n.default,{href:"/dashboard/cell-settings/imei-mangling",className:"".concat("/dashboard/cell-settings/imei-mangling/"===t?"font-semibold text-primary":"text-sm"),children:"IMEI Mangling"}),(0,a.jsx)(n.default,{href:"/dashboard/cell-settings/sms",className:"".concat("/dashboard/cell-settings/sms/"===t?"font-semibold text-primary":"text-sm"),children:"SMS Inbox"})]}),s]})]})}},27525:function(e,s,t){"use strict";var a=t(39886);t.o(a,"usePathname")&&t.d(s,{usePathname:function(){return a.usePathname}}),t.o(a,"useRouter")&&t.d(s,{useRouter:function(){return a.useRouter}})}},function(e){e.O(0,[6509,8985,5330,1744],function(){return e(e.s=37946)}),_N_E=e.O()}]);

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[5342],{97017:function(e,t,a){Promise.resolve().then(a.bind(a,98496))},98496:function(e,t,a){"use strict";a.r(t);var s=a(20881);a(64149);var r=a(27525),n=a(26509);t.default=e=>{let{children:t}=e,a=(0,r.usePathname)();return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("div",{className:"mx-auto grid w-full max-w-6xl gap-2",children:(0,s.jsx)("h1",{className:"text-3xl font-semibold",children:"Experimental"})}),(0,s.jsxs)("div",{className:"mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]",children:[(0,s.jsx)("nav",{className:"grid gap-4 text-sm text-muted-foreground","x-chunk":"dashboard-04-chunk-0",children:(0,s.jsx)(n.default,{href:"/dashboard/experimental/quecwatch",className:"".concat("/dashboard/experimental/quecwatch/"===a?"font-semibold text-primary":"text-sm"),children:"QuecWatch"})}),t]})]})}},27525:function(e,t,a){"use strict";var s=a(39886);a.o(s,"usePathname")&&a.d(t,{usePathname:function(){return s.usePathname}}),a.o(s,"useRouter")&&a.d(t,{useRouter:function(){return s.useRouter}})}},function(e){e.O(0,[6509,8985,5330,1744],function(){return e(e.s=97017)}),_N_E=e.O()}]);

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7387],{43682:function(){}},function(n){n.O(0,[8985,5330,1744],function(){return n(n.s=43682)}),_N_E=n.O()}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[813],{67238:function(e,t,s){Promise.resolve().then(s.bind(s,83746))},83746:function(e,t,s){"use strict";s.r(t);var a=s(20881);s(64149);var r=s(27525),n=s(26509);t.default=e=>{let{children:t}=e,s=(0,r.usePathname)();return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"mx-auto grid w-full max-w-6xl gap-2",children:(0,a.jsx)("h1",{className:"text-3xl font-semibold",children:"Settings"})}),(0,a.jsxs)("div",{className:"mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]",children:[(0,a.jsxs)("nav",{className:"grid gap-4 text-sm text-muted-foreground","x-chunk":"dashboard-04-chunk-0",children:[(0,a.jsx)(n.default,{href:"/dashboard/settings/general",className:"".concat("/dashboard/settings/general/"===s?"font-semibold text-primary":"text-sm"),children:"General"}),(0,a.jsx)(n.default,{href:"/dashboard/settings/security",className:"".concat("/dashboard/settings/security/"===s?"font-semibold text-primary":"text-sm"),children:"Security"})]}),t]})]})}},27525:function(e,t,s){"use strict";var a=s(39886);s.o(a,"usePathname")&&s.d(t,{usePathname:function(){return a.usePathname}}),s.o(a,"useRouter")&&s.d(t,{useRouter:function(){return a.useRouter}})}},function(e){e.O(0,[6509,8985,5330,1744],function(){return e(e.s=67238)}),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3197],{84773:function(a,t,h){h.d(t,{GWp:function(){return r}});var n=h(83111);function r(a){return(0,n.w_)({tag:"svg",attr:{fill:"currentColor",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"m11.646.44.897.896-1.703 1.703A1.5 1.5 0 0 0 10.5 3h-5A1.5 1.5 0 0 0 4 4.5v5.379l-2 2V1.5A1.5 1.5 0 0 1 3.5 0h7.086a1.5 1.5 0 0 1 1.06.44M8.5 5.378 9.879 4H8.5zM5 8.879 6.879 7H5zm6-1.758L9.121 9H11zm-3.5 3.5L6.121 12H7.5zM5.5 13q-.175 0-.34-.039L2.502 15.62c.265.236.615.38.998.38h9a1.5 1.5 0 0 0 1.5-1.5V4.121l-2 2V11.5a1.5 1.5 0 0 1-1.5 1.5zM5 4.5a.5.5 0 0 1 .5-.5h2v2H5zM8.5 10H11v1.5a.5.5 0 0 1-.5.5h-2zm6.354-8.146a.5.5 0 0 0-.708-.708l-13 13a.5.5 0 0 0 .708.708z"},child:[]}]})(a)}}}]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1744],{7137:function(e,n,t){Promise.resolve().then(t.t.bind(t,81013,23)),Promise.resolve().then(t.t.bind(t,78073,23)),Promise.resolve().then(t.t.bind(t,41626,23)),Promise.resolve().then(t.t.bind(t,16102,23)),Promise.resolve().then(t.t.bind(t,84262,23)),Promise.resolve().then(t.t.bind(t,22609,23))}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[8985,5330],function(){return n(90039),n(7137)}),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2888],{79452:function(n,_,u){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_app",function(){return u(84820)}])}},function(n){var _=function(_){return n(n.s=_)};n.O(0,[9774,179],function(){return _(79452),_(26699)}),_N_E=n.O()}]);

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[4820],{17022:function(n,_,u){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_error",function(){return u(63936)}])}},function(n){n.O(0,[2888,9774,179],function(){return n(n.s=17022)}),_N_E=n.O()}]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
!function(){"use strict";var e,t,n,r,o,u,i,c,f,a={},l={};function d(e){var t=l[e];if(void 0!==t)return t.exports;var n=l[e]={id:e,loaded:!1,exports:{}},r=!0;try{a[e].call(n.exports,n,n.exports,d),r=!1}finally{r&&delete l[e]}return n.loaded=!0,n.exports}d.m=a,e=[],d.O=function(t,n,r,o){if(n){o=o||0;for(var u=e.length;u>0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[n,r,o];return}for(var i=1/0,u=0;u<e.length;u++){for(var n=e[u][0],r=e[u][1],o=e[u][2],c=!0,f=0;f<n.length;f++)i>=o&&Object.keys(d.O).every(function(e){return d.O[e](n[f])})?n.splice(f--,1):(c=!1,o<i&&(i=o));if(c){e.splice(u--,1);var a=r();void 0!==a&&(t=a)}}return t},d.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return d.d(t,{a:t}),t},n=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},d.t=function(e,r){if(1&r&&(e=this(e)),8&r||"object"==typeof e&&e&&(4&r&&e.__esModule||16&r&&"function"==typeof e.then))return e;var o=Object.create(null);d.r(o);var u={};t=t||[null,n({}),n([]),n(n)];for(var i=2&r&&e;"object"==typeof i&&!~t.indexOf(i);i=n(i))Object.getOwnPropertyNames(i).forEach(function(t){u[t]=function(){return e[t]}});return u.default=function(){return e},d.d(o,u),o},d.d=function(e,t){for(var n in t)d.o(t,n)&&!d.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},d.f={},d.e=function(e){return Promise.all(Object.keys(d.f).reduce(function(t,n){return d.f[n](e,t),t},[]))},d.u=function(e){},d.miniCssF=function(e){},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r={},o="_N_E:",d.l=function(e,t,n,u){if(r[e]){r[e].push(t);return}if(void 0!==n)for(var i,c,f=document.getElementsByTagName("script"),a=0;a<f.length;a++){var l=f[a];if(l.getAttribute("src")==e||l.getAttribute("data-webpack")==o+n){i=l;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,d.nc&&i.setAttribute("nonce",d.nc),i.setAttribute("data-webpack",o+n),i.src=d.tu(e)),r[e]=[t];var s=function(t,n){i.onerror=i.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(function(e){return e(n)}),t)return t(n)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=s.bind(null,i.onerror),i.onload=s.bind(null,i.onload),c&&document.head.appendChild(i)},d.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.nmd=function(e){return e.paths=[],e.children||(e.children=[]),e},d.tt=function(){return void 0===u&&(u={createScriptURL:function(e){return e}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(u=trustedTypes.createPolicy("nextjs#bundler",u))),u},d.tu=function(e){return d.tt().createScriptURL(e)},d.p="/_next/",i={2272:0,736:0},d.f.j=function(e,t){var n=d.o(i,e)?i[e]:void 0;if(0!==n){if(n)t.push(n[2]);else if(/^(2272|736)$/.test(e))i[e]=0;else{var r=new Promise(function(t,r){n=i[e]=[t,r]});t.push(n[2]=r);var o=d.p+d.u(e),u=Error();d.l(o,function(t){if(d.o(i,e)&&(0!==(n=i[e])&&(i[e]=void 0),n)){var r=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;u.message="Loading chunk "+e+" failed.\n("+r+": "+o+")",u.name="ChunkLoadError",u.type=r,u.request=o,n[1](u)}},"chunk-"+e,e)}}},d.O.j=function(e){return 0===i[e]},c=function(e,t){var n,r,o=t[0],u=t[1],c=t[2],f=0;if(o.some(function(e){return 0!==i[e]})){for(n in u)d.o(u,n)&&(d.m[n]=u[n]);if(c)var a=c(d)}for(e&&e(t);f<o.length;f++)r=o[f],d.o(i,r)&&i[r]&&i[r][0](),i[r]=0;return d.O(a)},(f=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(c.bind(null,0)),f.push=c.bind(null,f.push.bind(f)),d.nc=void 0}();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
self.__BUILD_MANIFEST={__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/_error":["static/chunks/pages/_error-185f70b36b33d607.js"],sortedPages:["/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View File

@@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()

View File

@@ -1,328 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!-- Logo -->
<link rel="logo" href="favicon.ico" />
<link rel="stylesheet" href="css/bulma/bulma.scss" />
<link rel="stylesheet" href="css/bulma/css/bulma.min.css" />
<link rel="stylesheet" href="css/bulma/css/bulma.css" />
<link rel="stylesheet" href="css/custom.css" />
<!-- Font awesome icons -->
<script
src="https://kit.fontawesome.com/b0caedfab3.js"
crossorigin="anonymous"
></script>
<script src="js/styles/toggle-theme.js"></script>
<script src="/js/styles/nav-burger.js"></script>
<script src="/js/styles/modal-trigger.js"></script>
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script src="/js/about/fetch-data.js"></script>
<script>
(function () {
const savedTheme = localStorage.getItem("theme") || "theme-dark";
document.documentElement.classList.add(savedTheme);
})();
</script>
<title>QuecManager</title>
</head>
<body class="body-margin">
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/assets/logo.png" alt="Logo" />
<span class="title">QuecManager</span>
</a>
<a
role="button"
class="navbar-burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start ml-6">
<a class="navbar-item" href="/"> Home </a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Cellular </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/cell-settings.html"
>Cell Settings</a
>
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Advance </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/advance-settings.html">
Advance Settings
</a>
<a class="navbar-item" href="#">Experimental Features</a>
<a class="navbar-item" href="/cgi-bin/luci">OpenWRT Luci</a>
</div>
</div>
<a class="navbar-item has-text-weight-bold" href="/about.html">
About
</a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-flex-direction-column-mobile">
<div class="control is-expanded-mobile">
<div
id="restartConnectionBtn"
class="button is-link is-outlined is-fullwidth-mobile"
>
<span class="icon">
<i class="fas fa-arrows-rotate"></i>
</span>
<span>Restart Connection</span>
</div>
</div>
<div class="is-flex is-mobile is-align-items-center">
<div class="control">
<div
class="button is-warning is-outlined reboot-modal"
data-target="reboot-modal"
>
<span class="icon">
<i class="fas fa-power-off"></i>
</span>
</div>
</div>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
>
<span class="icon">
<i class="fas fa-sun"></i>
</span>
</a>
</p>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
id="logoutButton"
>
<span class="icon">
<i class="fas fa-right-from-bracket"></i>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="column-margin">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid">
<div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">Device Information</div>
</div>
<div class="card-content">
<table class="table is-fullwidth is-borderless">
<tbody>
<tr>
<td>Modem Manufacturer</td>
<th id="manufacturer">Fetching...</th>
</tr>
<tr>
<td>Modem Model Name</td>
<th id="model"></th>
</tr>
<tr>
<td>Firmware Version</td>
<th id="firmwareVersion"></th>
</tr>
<tr>
<td>LTE Category</td>
<th id="lteCategory"></th>
</tr>
<tr>
<td>Phone Number</td>
<th id="phoneNumber"></th>
</tr>
<tr>
<td>IMSI</td>
<th id="imsi"></th>
</tr>
<tr>
<td>ICCID</td>
<th id="iccid"></th>
</tr>
<tr>
<td>IMEI</td>
<th>
<div class="field has-addons is-hidden-mobile">
<div class="control">
<input
class="input has-text-weight-semibold"
type="text"
placeholder="IMEI Here"
id="imeiInput"
/>
</div>
<div class="control">
<button class="button is-link" id="changeButton">Change</button>
</div>
</div>
<span class="is-block-mobile is-hidden" id="imei">
</span>
</th>
</tr>
<tr>
<td>LAN GATEWAY</td>
<th id="lanIP">
</th>
</tr>
<tr>
<td>WWAN IPv4</td>
<th id="IPv4">
</th>
</tr>
<tr>
<td>WWAN IPv6</td>
<th style="word-break: break-all" id="IPv6">
</th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">About Us</div>
</div>
<div class="card-content">
<div class="content">
<p class="title">QuecManager</p>
<p class="subtitle mt-2">
Simple Admin began as part of the RGMII toolkit, offering
users a basic GUI. However, with our fork and continued
development, it has evolved to include more advanced
features, making "simple" no longer an ideal name for the
dashboard. Despite this shift, we remain committed to
providing advanced functionality while maintaining an
intuitive and user-friendly GUI.
</p>
<p class="subtitle mt-6 has-text-weight-bold">Thanks to</p>
<ul class="has-text-weight-semibold">
<li>
RGMII Toolkit and Documentation
<a href="https://github.com/iamromulan" target="_blank"
>iamromulan</a
>
</li>
<li>
Simple Admin 2.0 and QuecManager
<a href="https://github.com/dr-dolomite" target="_blank"
>dr-dolomite</a
>
</li>
<li>
SMS Feature
<a href="https://github.com/snjzb" target="_blank"
>snjzb</a
>
</li>
<li>
Original Simple Admin
<a href="https://github.com/aesthernr" target="_blank"
>aesthernr</a
>
</li>
<li>
Original Socat Bridge
<a href="https://github.com/natecarlson" target="_blank"
>natecarlson</a
>
</li>
<li>
Initial Original Simple Admin Fixes
<a href="https://github.com/rbflurry/" target="_blank"
>rbflurry</a
>
</li>
<li>
Wutang Clan
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="content has-text-centered">
<p>
<strong>
<a href="https://github.com/iamromulan/quectel-rgmii-toolkit.git"
>QuecManager</a
></strong
>
version 1.0. All rights reserved.
</p>
</div>
</footer>
<div id="reboot-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do not do any action while the modem is rebooting.
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">80</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">
<button class="button is-warning" id="rebootModem">Reboot</button>
<button class="button cancel" aria-label="close">Cancel</button>
</div>
</section>
</div>
</div>
</body>
</html>

View File

@@ -1,532 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!-- Logo -->
<link rel="simpleadmin-logo" href="favicon.ico" />
<link rel="stylesheet" href="css/bulma/bulma.scss" />
<link rel="stylesheet" href="css/bulma/css/bulma.min.css" />
<link rel="stylesheet" href="css/bulma/css/bulma.css" />
<link rel="stylesheet" href="css/custom.css" />
<!-- Font awesome icons -->
<script
src="https://kit.fontawesome.com/b0caedfab3.js"
crossorigin="anonymous"
></script>
<script src="js/styles/toggle-theme.js"></script>
<script src="/js/styles/nav-burger.js"></script>
<script src="/js/styles/modal-trigger.js"></script>
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script src="/js/advance/at-terminal.js"></script>
<script src="/js/advance/ttl-control.js"></script>
<script src="/js/advance/fetch-current-settings.js"></script>
<script>
(function () {
const savedTheme = localStorage.getItem("theme") || "theme-dark";
document.documentElement.classList.add(savedTheme);
})();
</script>
<title>QuecManager</title>
</head>
<body class="body-margin">
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/assets/logo.png" alt="Logo" />
<span class="title">QuecManager</span>
</a>
<a
role="button"
class="navbar-burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start ml-6">
<a class="navbar-item" href="/"> Home </a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Cellular </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/cell-settings.html"
>Cell Settings</a
>
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link has-text-weight-bold"> Advance </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/advance-settings.html">
Advance Settings
</a>
<a class="navbar-item" href="#">Experimental Features</a>
<a class="navbar-item" href="/cgi-bin/luci">OpenWRT Luci</a>
</div>
</div>
<a class="navbar-item" href="/about.html"> About </a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-flex-direction-column-mobile">
<div class="control is-expanded-mobile">
<div
id="restartConnectionBtn"
class="button is-link is-outlined is-fullwidth-mobile"
>
<span class="icon">
<i class="fas fa-arrows-rotate"></i>
</span>
<span>Restart Connection</span>
</div>
</div>
<div class="is-flex is-mobile is-align-items-center">
<div class="control">
<div
class="button is-warning is-outlined reboot-modal"
data-target="reboot-modal"
>
<span class="icon">
<i class="fas fa-power-off"></i>
</span>
</div>
</div>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
>
<span class="icon">
<i class="fas fa-sun"></i>
</span>
</a>
</p>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
id="logoutButton"
>
<span class="icon">
<i class="fas fa-right-from-bracket"></i>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="column-margin">
<div class="columns">
<div class="column">
<div class="card">
<div class="card-header">
<p class="card-header-title">AT Command Terminal</p>
</div>
<div class="card-content">
<form id="commandForm">
<div class="field">
<label class="label">Output</label>
<div class="control">
<textarea
class="textarea"
id="output"
rows="10"
readonly
placeholder="AT command responses will appear here..."
></textarea>
</div>
</div>
<div class="field is-hidden-touch">
<div class="level">
<div class="level-left">
<div class="level-item">
<label class="label">Command History</label>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button
type="button"
id="clearHistory"
class="button is-small is-link has-text-white"
>
Clear All
</button>
</div>
</div>
</div>
<div class="command-history" id="commandHistory">
<div class="no-history" id="noHistory">No commands yet</div>
</div>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<input
class="input"
type="text"
id="command"
placeholder="Enter AT command (e.g., ATI)"
autocomplete="off"
/>
</div>
<div class="control" style="position: relative">
<button
type="submit"
class="button is-link"
id="sendButton"
>
<span class="icon">
<i class="fas fa-paper-plane"></i>
</span>
<span>Send</span>
</button>
<span id="cooldownTimer"></span>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="column">
<div class="card">
<div class="card-header">
<div class="card-header-title">Advance Settings</div>
</div>
<div class="card-content">
<div class="fixed-grid has-1-cols">
<div class="grid is-gap-5">
<div class="cell advanced-settings">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid">
<div class="cell is-col-span-2 is-col-span-1-mobile">
<div class="columns">
<div class="column">
<div class="field">
<label class="label">IP Passthrough Mode</label>
<p class="control has-icons-left">
<span class="select">
<select id="ip-passthrough-mode">
<option value="placeholder" selected>
Select IP Passthrough Mode
</option>
<option value="Disabled">Disabled</option>
<option value="ETH Only">ETH Only</option>
<option value="USB Only">USB Only</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-ethernet"></i>
</span>
</p>
<p class="help">
This will reboot the device to apply changes.
</p>
</div>
</div>
<div class="column">
<div class="field">
<label class="label"
>Connected Devices MAC</label
>
<p class="control has-icons-left">
<span class="select">
<select id="connected-devices">
<option selected>
Select Device MAC
</option>
<!-- Populate the options here -->
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-laptop"></i>
</span>
</p>
<p class="help">
Selecting a device first before enabling.
</p>
</div>
</div>
</div>
</div>
<div class="cell advanced-settings">
<div class="field">
<label class="label">USB Modem Protocol</label>
<p class="control has-icons-left">
<span class="select">
<select id="usb-modem-protocol">
<option selected>
Select USB Modem Protocol
</option>
<option value="RMNET">RMNET</option>
<option value="ECM (Recommended)">
ECM (Recommended)
</option>
<option value="MBIM">MBIM</option>
<option value="RNDIS">RNDIS</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-network-wired"></i>
</span>
</p>
<p class="help">
Selecting a mode will apply immediately. Requires
reboot.
</p>
</div>
</div>
<div class="cell advanced-settings">
<div class="field">
<label class="label">Onboard DNS Proxy Mode</label>
<p class="control has-icons-left">
<span class="select">
<select id="dns-proxy-mode">
<option selected>
Select Onboard DNS Proxy
</option>
<option value="Enabled">Enabled</option>
<option value="Disabled">Disabled</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-server"></i>
</span>
</p>
<p class="help">
Selecting a mode will apply immediately.
</p>
</div>
</div>
</div>
</div>
</div>
<!-- <div class="cell">
<div class="fixed-grid has-2-cols">
<div class="grid is-gap-3">
<div class="cell">
<div class="field">
<label class="label">TTL State</label>
<div class="control has-icons-right">
<input
class="input is-danger"
placeholder="Disabled"
disabled
/>
<span class="icon is-small is-right">
<i class="fas fa-exclamation-triangle"></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">TTL Value</label>
<div class="control has-icons-right">
<input
class="input is-danger"
placeholder="0"
disabled
/>
<span class="icon is-small is-right">
<i class="fas fa-exclamation-triangle"></i>
</span>
</div>
</div>
</div>
<div class="cell is-col-span-2">
<div class="field">
<label class="label">TTL Value to Set</label>
<div class="control has-icons-left">
<input
class="input"
type="number"
placeholder="Custom TTL Value"
value="bulma"
/>
<span class="icon is-small is-left">
<i class="fas fa-wifi"></i>
</span>
</div>
<p class="help is-success has-text-weight-semibold">
Set the TTL Value to 0 to disable.
</p>
</div>
</div>
</div>
</div>
</div> -->
<div class="cell">
<div class="fixed-grid has-2-cols">
<div class="grid is-gap-3">
<div class="cell">
<div class="field">
<label class="label">TTL State</label>
<div class="control has-icons-right">
<input
id="ttl-state"
class="input is-warning has-text-weight-bold"
placeholder="Disabled"
disabled
/>
<span class="icon is-small is-right">
<i
class="fas fa-exclamation-triangle has-text-warning"
></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">Current TTL Value</label>
<div class="control has-icons-right">
<input
id="ttl-current-value"
class="input is-warning has-text-weight-bold has-text-white"
placeholder="0"
disabled
/>
<span class="icon is-small is-right">
<i
class="fas fa-exclamation-triangle has-text-warning"
></i>
</span>
</div>
</div>
</div>
<div class="cell is-col-span-2">
<div class="field">
<label class="label">TTL Value to Set</label>
<div class="control has-icons-left">
<input
id="ttl-set-value"
class="input"
type="number"
placeholder="Custom TTL Value"
/>
<span class="icon is-small is-left">
<i class="fas fa-wifi"></i>
</span>
</div>
<p class="help is-success has-text-weight-semibold">
Set the TTL Value to 0 to disable.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<a
id="ttl-submit"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Apply TTL Settings
</a>
<a
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="content">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid">
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Information</span>
</div>
<p class="block has-text-weight-semibold">
Use AT custom commands only if you know what you are doing.
</p>
</div>
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Information</span>
</div>
<p class="block has-text-weight-semibold">
Selecting a mode will apply immediately and will also disconnect
from the network.
</p>
</div>
</div>
</div>
</div>
</footer>
<div id="reboot-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do not do any action while the modem is rebooting.
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">90</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">
<button class="button is-warning" id="rebootModem">Reboot</button>
<button class="button cancel" aria-label="close">Cancel</button>
</div>
</section>
</div>
</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,680 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!-- Logo -->
<link rel="simpleadmin-logo" href="favicon.ico" />
<link rel="stylesheet" href="css/bulma/bulma.scss" />
<link rel="stylesheet" href="css/bulma/css/bulma.min.css" />
<link rel="stylesheet" href="css/bulma/css/bulma.css" />
<link rel="stylesheet" href="css/custom.css" />
<!-- Font awesome icons -->
<script
src="https://kit.fontawesome.com/b0caedfab3.js"
crossorigin="anonymous"
></script>
<script src="js/styles/toggle-theme.js"></script>
<script src="/js/styles/nav-burger.js"></script>
<script src="/js/styles/modal-trigger.js"></script>
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script src="/js/band-locking/fetch-bands.js"></script>
<script>
(function () {
const savedTheme = localStorage.getItem("theme") || "theme-dark";
document.documentElement.classList.add(savedTheme);
})();
</script>
<title>QuecManager</title>
</head>
<body class="body-margin">
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/assets/logo.png" alt="Logo" />
<span class="title">QuecManager</span>
</a>
<a
role="button"
class="navbar-burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start ml-6">
<a class="navbar-item" href="/"> Home </a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link has-text-weight-bold"> Cellular </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/cell-settings.html"
>Cell Settings</a
>
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Advance </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/advance-settings.html">
Advance Settings
</a>
<a class="navbar-item" href="#">Experimental Features</a>
<a class="navbar-item" href="/cgi-bin/luci">OpenWRT Luci</a>
</div>
</div>
<a class="navbar-item" href="/about.html"> About </a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-flex-direction-column-mobile">
<div class="control is-expanded-mobile">
<div
id="restartConnectionBtn"
class="button is-link is-outlined is-fullwidth-mobile"
>
<span class="icon">
<i class="fas fa-arrows-rotate"></i>
</span>
<span>Restart Connection</span>
</div>
</div>
<div class="is-flex is-mobile is-align-items-center">
<div class="control">
<div
class="button is-warning is-outlined reboot-modal"
data-target="reboot-modal"
>
<span class="icon">
<i class="fas fa-power-off"></i>
</span>
</div>
</div>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
>
<span class="icon">
<i class="fas fa-sun"></i>
</span>
</a>
</p>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
id="logoutButton"
>
<span class="icon">
<i class="fas fa-right-from-bracket"></i>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="column-margin">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid is-gap-5">
<div class="cell is-col-span-2 is-col-span-1-mobile">
<div class="card">
<div class="card-header">
<div class="card-header-title">4G LTE Band Locking</div>
</div>
<div class="card-content">
<div class="fixed-grid has-5-cols has-3-cols-mobile">
<div class="grid" id="lte_bands">
<!-- LTE bands will be populated here -->
</div>
</div>
</div>
<div class="card-footer">
<a
id="lockLte"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Lock LTE Bands
</a>
<a
id="uncheckLte"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Uncheck All
</a>
<a
id="resetLte"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div>
<!-- <div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">5G-NR SA Band Locking</div>
</div>
<div class="card-content">
<div class="fixed-grid has-5-cols has-3-cols-mobile">
<div class="grid" id="sa_bands">
</div>
</div>
</div>
<div class="card-footer">
<a
id="lockSa"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Lock SA Bands
</a>
<a
id="uncheckSa"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Uncheck All
</a>
<a
id="resetSa"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div> -->
<div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">5G-NR NSA Band Locking</div>
</div>
<div class="card-content">
<div class="fixed-grid has-5-cols has-3-cols-mobile">
<div class="grid" id="nsa_bands">
<!-- NSA bands will be populated here -->
</div>
</div>
</div>
<div class="card-footer">
<a
id="lockNsa"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Lock NSA Bands
</a>
<a
id="uncheckNsa"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Uncheck All
</a>
<a
id="resetNsa"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div>
<div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">5G-NR SA-DC Band Locking</div>
</div>
<div class="card-content">
<div class="fixed-grid has-5-cols has-3-cols-mobile">
<div class="grid" id="sanrdc_bands">
<!-- SA bands will be populated here -->
</div>
</div>
</div>
<div class="card-footer">
<a
id="lockSaDc"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Lock SA-DC Bands
</a>
<a
id="uncheckSaDc"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Uncheck All
</a>
<a
id="resetSaDc"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="content">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid">
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Information</span>
</div>
<p class="block has-text-weight-semibold">
If problem persists after locking bands, please reboot the
modem.
</p>
</div>
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Current Active Bands</span>
</div>
<p class="block has-text-weight-semibold" id="currentBands"></p>
</div>
</div>
</div>
</div>
</footer>
<div id="reboot-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do you want to reboot the device?
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">90</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">
<button class="button is-warning" id="rebootModem">Reboot</button>
<button class="button cancel" aria-label="close">Cancel</button>
</div>
</section>
</div>
</div>
<!-- <script>
// Function to fetch current active bands and display them in the footer
async function fetchCurrentBands() {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent("AT+QCAINFO"),
});
const data = await response.json();
// Extract active bands
// Find the lines that contains "LTE BAND <band number>" or "NR5G BAND <band number>" and append them to the currentBands variable
const lteBands = data.output.match(/LTE BAND ([0-9]+)/g) || [];
const nrBands = data.output.match(/NR5G BAND ([0-9]+)/g) || [];
// Combine the two arrays and join them with a comma
if (lteBands.length === 0 && nrBands.length === 0) {
document.getElementById("currentBands").textContent =
"No active bands found";
return;
} else if (lteBands.length === 0) {
document.getElementById("currentBands").textContent =
nrBands.join(", ");
return;
} else if (nrBands.length === 0) {
document.getElementById("currentBands").textContent =
lteBands.join(", ");
return;
} else {
document.getElementById("currentBands").textContent = [
...lteBands,
...nrBands,
].join(", ");
}
} catch (error) {
console.error("Error fetching current bands:", error);
}
}
// Function to fetch supported bands via AT command and populate the checkboxes
async function fetchSupportedBands() {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body:
"command=" + encodeURIComponent('AT+QNWPREFCFG="policy_band"'),
});
const data = await response.json();
const lteBandsMatch = data.output.match(/"lte_band",([0-9:]+)/);
const nsaBandsMatch = data.output.match(/"nsa_nr5g_band",([0-9:]+)/);
// const saBandsMatch = data.output.match(/"nr5g_band",([0-9:]+)/);
const saDcBandsMatch = data.output.match(
/"nrdc_nr5g_band",([0-9:]+)/
);
if (lteBandsMatch) populateBands(lteBandsMatch[1], "#lte_bands");
// if (saBandsMatch) populateBands(saBandsMatch[1], "#sa_bands");
if (nsaBandsMatch) populateBands(nsaBandsMatch[1], "#nsa_bands");
if (saDcBandsMatch) populateBands(saDcBandsMatch[1], "#sanrdc_bands");
fetchActiveBands();
} catch (error) {
console.error("Error fetching supported bands:", error);
}
}
// Function to fetch currently active bands and mark the checkboxes accordingly
async function fetchActiveBands() {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body:
"command=" +
encodeURIComponent(
'AT+QNWPREFCFG="lte_band";+QNWPREFCFG="nsa_nr5g_band";+QNWPREFCFG="nr5g_band";+QNWPREFCFG="nrdc_nr5g_band"'
),
});
const data = await response.json();
// Remove the first line of the output
data.output = data.output.split("\n").slice(1).join("\n");
// Remove "OK" line
data.output = data.output.replace("OK", "");
console.log(data.output);
// Extract active bands
const activeLteBands = data.output
.match(/"lte_band",([0-9:]+)/)[1]
.split(":");
const activeNsaBands = data.output
.match(/"nsa_nr5g_band",([0-9:]+)/)[1]
.split(":");
// const activeSaBands = data.output
// .match(/"nr5g_band",([0-9:]+)/)[1]
// .split(":");
// get the the second to the last line of the output and use it for active sa-dc bands
const activeSaDcBandsLine = data.output
.split("\n")[6]
.match(/"nr5g_band",([0-9:]+)/)[1]
.split(":");
// // Mark checkboxes as checked for active bands
markActiveBands(activeLteBands, "#lte_bands");
markActiveBands(activeNsaBands, "#nsa_bands");
// markActiveBands(activeSaBands, "#sa_bands");
markActiveBands(activeSaDcBandsLine, "#sanrdc_bands");
// Fetch current active bands and display them in the footer
fetchCurrentBands();
} catch (error) {
console.error("Error fetching active bands:", error);
}
}
// Function to populate bands in the target element
function populateBands(bandsString, targetId) {
var bandsArray = bandsString.split(":");
var html = "";
for (var i = 0; i < bandsArray.length; i++) {
html += `<div class="cell">
<label class="checkbox">
<input type="checkbox" value="${bandsArray[i]}" /> B${bandsArray[i]}
</label>
</div>`;
}
document.querySelector(targetId).innerHTML = html;
}
// Function to mark checkboxes as checked based on active bands
function markActiveBands(activeBands, targetId) {
const checkboxes = document.querySelectorAll(
`${targetId} input[type="checkbox"]`
);
checkboxes.forEach((checkbox) => {
if (activeBands.includes(checkbox.value)) {
checkbox.setAttribute("checked", "checked");
}
});
}
// Function to uncheck all checkboxes in the target element
function uncheckAll(targetId) {
const checkboxes = document.querySelectorAll(
`${targetId} input[type="checkbox"]`
);
checkboxes.forEach((checkbox) => {
checkbox.removeAttribute("checked");
checkbox.checked = false; // Also update the state programmatically
});
}
// Event listeners for "Uncheck All" buttons
document
.getElementById("uncheckLte")
.addEventListener("click", function (event) {
event.preventDefault();
uncheckAll("#lte_bands");
});
document
.getElementById("uncheckNsa")
.addEventListener("click", function (event) {
event.preventDefault();
uncheckAll("#nsa_bands");
});
// document
// .getElementById("uncheckSa")
// .addEventListener("click", function (event) {
// event.preventDefault();
// uncheckAll("#sa_bands");
// });
document
.getElementById("uncheckSaDc")
.addEventListener("click", function (event) {
event.preventDefault();
uncheckAll("#sanrdc_bands");
});
// Locking the Bands
// Function to get checked bands and generate AT command
function getCheckedBandsCommand(targetId, commandType) {
const checkboxes = document.querySelectorAll(
`${targetId} input[type="checkbox"]:checked`
);
const checkedBands = Array.from(checkboxes)
.map((cb) => cb.value)
.sort((a, b) => a - b);
if (checkedBands.length === 0) {
return null; // Return null if no bands are selected
}
const bandString = checkedBands.join(":");
return `AT+QNWPREFCFG="${commandType}",${bandString}`;
}
// Function to send AT command via atinout
async function sendATCommand(command) {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: `command=${encodeURIComponent(command)}`,
});
const data = await response.json();
return data;
// refetch active bands after successful command
fetchActiveBands();
} catch (error) {
console.error("Error sending AT command:", error);
throw error;
}
}
// Function to handle band locking for a specific type
async function lockBands(targetId, commandType) {
const command = getCheckedBandsCommand(targetId, commandType);
if (!command) {
alert("Please select at least one band to lock.");
return;
}
try {
await sendATCommand(command);
alert(
`Successfully locked ${commandType
.split("_")[0]
.toUpperCase()} bands`
);
} catch (error) {
alert(`Failed to lock bands: ${error.message}`);
}
}
// Event listeners for Lock buttons
document
.getElementById("lockLte")
.addEventListener("click", () => lockBands("#lte_bands", "lte_band"));
document
.getElementById("lockNsa")
.addEventListener("click", () =>
lockBands("#nsa_bands", "nsa_nr5g_band")
);
document
.getElementById("lockSa")
.addEventListener("click", () => lockBands("#sa_bands", "nr5g_band"));
document
.getElementById("lockSaDc")
.addEventListener("click", () =>
lockBands("#sanrdc_bands", "nrdc_nr5g_band")
);
// Event listeners for Reset buttons
// Function to reset and check all checkboxes for a given band type
function resetBands(targetId, bandType) {
const checkboxes = document.querySelectorAll(
`${targetId} input[type="checkbox"]`
);
let selectedBands = [];
// Check all checkboxes and gather their values
checkboxes.forEach((checkbox) => {
checkbox.setAttribute("checked", "checked");
checkbox.checked = true;
selectedBands.push(checkbox.value);
});
// Create and send the AT command with all bands
sendBandLockCommand(selectedBands, bandType);
}
// Function to send the AT command to lock the bands
async function sendBandLockCommand(bands, bandType) {
// Join the selected bands with ":" separator for the AT command
const bandString = bands.join(":");
const command = `AT+QNWPREFCFG="${bandType}",${bandString}`;
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command),
});
const data = await response.json();
console.log(
`Band lock command for ${bandType} executed:`,
data.output
);
} catch (error) {
console.error(
`Error sending band lock command for ${bandType}:`,
error
);
}
}
// Event listeners for "Reset" buttons
document
.getElementById("resetLte")
.addEventListener("click", function (event) {
event.preventDefault();
resetBands("#lte_bands", "lte_band");
});
document
.getElementById("resetNsa")
.addEventListener("click", function (event) {
event.preventDefault();
resetBands("#nsa_bands", "nsa_nr5g_band");
});
document
.getElementById("resetSa")
.addEventListener("click", function (event) {
event.preventDefault();
resetBands("#sa_bands", "nr5g_band");
});
document
.getElementById("resetSaDc")
.addEventListener("click", function (event) {
event.preventDefault();
resetBands("#sanrdc_bands", "nrdc_nr5g_band");
});
// Initial call to fetch supported bands on page load
window.onload = fetchSupportedBands;
</script> -->
</body>
</html>

View File

@@ -1,450 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!-- Logo -->
<link rel="simpleadmin-logo" href="favicon.ico" />
<link rel="stylesheet" href="css/bulma/bulma.scss" />
<link rel="stylesheet" href="css/bulma/css/bulma.min.css" />
<link rel="stylesheet" href="css/bulma/css/bulma.css" />
<link rel="stylesheet" href="css/custom.css" />
<!-- Font awesome icons -->
<script
src="https://kit.fontawesome.com/b0caedfab3.js"
crossorigin="anonymous"
></script>
<script src="js/styles/toggle-theme.js"></script>
<script src="/js/styles/nav-burger.js"></script>
<script src="/js/styles/modal-trigger.js"></script>
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script src="/js/cell-locking/cell-lock.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script>
(function () {
const savedTheme = localStorage.getItem("theme") || "theme-dark";
document.documentElement.classList.add(savedTheme);
})();
</script>
<title>QuecManager</title>
</head>
<body class="body-margin">
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/assets/logo.png" alt="Logo" />
<span class="title">QuecManager</span>
</a>
<a
role="button"
class="navbar-burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start ml-6">
<a class="navbar-item" href="/"> Home </a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link has-text-weight-bold"> Cellular </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/cell-settings.html"
>Cell Settings</a
>
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Advance </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/advance-settings.html">
Advance Settings
</a>
<a class="navbar-item" href="#">Experimental Features</a>
<a class="navbar-item" href="/cgi-bin/luci">OpenWRT Luci</a>
</div>
</div>
<a class="navbar-item" href="/about.html"> About </a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-flex-direction-column-mobile">
<div class="control is-expanded-mobile">
<div
id="restartConnectionBtn"
class="button is-link is-outlined is-fullwidth-mobile"
>
<span class="icon">
<i class="fas fa-arrows-rotate"></i>
</span>
<span>Restart Connection</span>
</div>
</div>
<div class="is-flex is-mobile is-align-items-center">
<div class="control">
<div
class="button is-warning is-outlined reboot-modal"
data-target="reboot-modal"
>
<span class="icon">
<i class="fas fa-power-off"></i>
</span>
</div>
</div>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
>
<span class="icon">
<i class="fas fa-sun"></i>
</span>
</a>
</p>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
id="logoutButton"
>
<span class="icon">
<i class="fas fa-right-from-bracket"></i>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="column-margin">
<div class="columns">
<div class="column">
<div class="card">
<div class="card-header">
<div class="card-header-title">4G LTE Cell Locking</div>
</div>
<div class="card-content">
<div class="fixed-grid has-2-cols">
<div class="grid">
<!-- Entry 1 Start -->
<div class="cell">
<div class="field">
<label class="label">EARFCN 1</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
id="earfcn1"
placeholder="EARFCN"
/>
<span class="icon is-left">
<i class="fas fa-bolt"></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">PCI 1</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="PCI"
id="pci1"
/>
<span class="icon is-left">
<i class="fa-solid fa-signal"></i>
</span>
</div>
</div>
</div>
<!-- Entry 1 End -->
<!-- Entry 2 Start -->
<div class="cell">
<div class="field">
<label class="label">EARFCN 2</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="EARFCN"
id="earfcn2"
/>
<span class="icon is-left">
<i class="fas fa-bolt"></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">PCI 2</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="PCI"
id="pci2"
/>
<span class="icon is-left">
<i class="fa-solid fa-signal"></i>
</span>
</div>
</div>
</div>
<!-- Entry 2 End -->
<!-- Entry 3 Start -->
<div class="cell">
<div class="field">
<label class="label">EARFCN 3</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="EARFCN"
id="earfcn3"
/>
<span class="icon is-left">
<i class="fas fa-bolt"></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">PCI 3</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="PCI"
id="pci3"
/>
<span class="icon is-left">
<i class="fa-solid fa-signal"></i>
</span>
</div>
</div>
</div>
<!-- Entry 3 End -->
</div>
</div>
</div>
<div class="card-footer">
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
id="saveLTE"
>
Lock LTE Cells
</a>
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
id="resetLTE"
>
Reset
</a>
</div>
</div>
</div>
<div class="column">
<div class="card">
<div class="card-header">
<div class="card-header-title">5G-NR SA Cell Locking</div>
</div>
<div class="card-content">
<div class="fixed-grid has-2-cols">
<div class="grid">
<!-- Entry 1 Start -->
<div class="cell">
<div class="field">
<label class="label">NR ARFCN</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="NR-ARFCN"
id="nr-arfcn"
/>
<span class="icon is-left">
<i class="fas fa-bolt"></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">NR PCI</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="NR PCI"
id="nr-pci"
/>
<span class="icon is-left">
<i class="fa-solid fa-signal"></i>
</span>
</div>
</div>
</div>
<!-- Entry 1 End -->
<!-- Entry 2 Start -->
<div class="cell">
<div class="field">
<label class="label">SCS</label>
<div class="control has-icons-left">
<span class="select">
<select id="scs">
<option selected>Select SCS</option>
<option value="15">15 kHz</option>
<option value="30">30 kHz</option>
<option value="60">60 kHz</option>
<option value="120">120 kHz</option>
<option value="240">240 kHz</option>
</select>
</span>
<span class="icon is-left">
<i class="fas fa-bolt"></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">NR Band</label>
<div class="control has-icons-left">
<input
class="input"
type="email"
placeholder="NR Band"
id="nr-band"
/>
<span class="icon is-left">
<i class="fa-solid fa-signal"></i>
</span>
</div>
</div>
</div>
<!-- Entry 2 End -->
</div>
</div>
</div>
<div class="card-footer">
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
id="saveSA"
>
Lock SA Cells
</a>
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
id="resetSA"
>
Reset
</a>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="content">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid">
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Information</span>
</div>
<p class="block has-text-weight-semibold">
Cell locking is an advance feature and may cause network
interruptions. <br />
Cell locking will also only work with the main band (PCC) if you
are using carrier aggregation.
<br />
Proceed with caution.
</p>
</div>
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>NR-5G Cell Locking</span>
</div>
<p class="block has-text-weight-semibold">
The NR-5G cell locking feature is only available on 5G-NR SA mode. <br />
This will also change the preferred network mode to NR5G.
</p>
</div>
</div>
</div>
</div>
</footer>
<div id="reboot-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do you want to reboot the device?
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">90</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">
<button class="button is-warning" id="rebootModem">Reboot</button>
<button class="button cancel" aria-label="close">Cancel</button>
</div>
</section>
</div>
</div>
</body>
</html>

View File

@@ -1,312 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!-- Logo -->
<link rel="simpleadmin-logo" href="favicon.ico" />
<link rel="stylesheet" href="css/bulma/bulma.scss" />
<link rel="stylesheet" href="css/bulma/css/bulma.min.css" />
<link rel="stylesheet" href="css/bulma/css/bulma.css" />
<link rel="stylesheet" href="css/custom.css" />
<!-- Font awesome icons -->
<script
src="https://kit.fontawesome.com/b0caedfab3.js"
crossorigin="anonymous"
></script>
<script src="js/styles/toggle-theme.js"></script>
<script src="/js/styles/nav-burger.js"></script>
<script src="/js/styles/modal-trigger.js"></script>
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script src="/js/cell-scanner/cell-scanner.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script>
(function () {
const savedTheme = localStorage.getItem("theme") || "theme-dark";
document.documentElement.classList.add(savedTheme);
})();
</script>
<title>QuecManager</title>
</head>
<body class="body-margin">
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/assets/logo.png" alt="Logo" />
<span class="title">QuecManager</span>
</a>
<a
role="button"
class="navbar-burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start ml-6">
<a class="navbar-item" href="/"> Home </a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link has-text-weight-bold"> Cellular </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/cell-settings.html"
>Cell Settings</a
>
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Advance </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/advance-settings.html">
Advance Settings
</a>
<a class="navbar-item" href="#">Experimental Features</a>
<a class="navbar-item" href="/cgi-bin/luci">OpenWRT Luci</a>
</div>
</div>
<a class="navbar-item" href="/about.html"> About </a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-flex-direction-column-mobile">
<div class="control is-expanded-mobile">
<div
id="restartConnectionBtn"
class="button is-link is-outlined is-fullwidth-mobile"
>
<span class="icon">
<i class="fas fa-arrows-rotate"></i>
</span>
<span>Restart Connection</span>
</div>
</div>
<div class="is-flex is-mobile is-align-items-center">
<div class="control">
<div
class="button is-warning is-outlined reboot-modal"
data-target="reboot-modal"
>
<span class="icon">
<i class="fas fa-power-off"></i>
</span>
</div>
</div>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
>
<span class="icon">
<i class="fas fa-sun"></i>
</span>
</a>
</p>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
id="logoutButton"
>
<span class="icon">
<i class="fas fa-right-from-bracket"></i>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="column-margin">
<div class="fixed-grid has-1-cols">
<div class="grid is-gap-5">
<div class="cell">
<div class="card">
<div class="card-header">
<p class="card-header-title">
Full Network Provider Cell Scanner
</p>
</div>
<div class="card-content">
<!-- <table class="table is-fullwidth">
<thead>
<tr>
<th>Network Provider</th>
<th>Name</th>
<th>EARFCN</th>
<th>Bandwidth</th>
<th>Physical ID</th>
<th class="is-hidden-mobile">RSRP</th>
<th class="is-hidden-mobile">RSRQ</th>
<th class="is-hidden-mobile">SINR</th>
</tr>
</thead>
<tbody id="fullCellScanTableBody">
<tr>
<td>Smart</td>
<td>B1</td>
<td>150</td>
<td>10</td>
<td>623</td>
<td class="is-hidden-mobile">
<div class="tags has-addons">
<span class="tag is-size-6">-103</span>
<span class="tag is-danger is-size-6 has-text-white"
>Poor</span
>
</div>
</td>
<td class="is-hidden-mobile">
<div class="tags has-addons">
<span class="tag is-size-6">-103</span>
<span class="tag is-danger is-size-6 has-text-white"
>Poor</span
>
</div>
</td>
<td class="is-hidden-mobile">
<div class="tags has-addons">
<span class="tag is-size-6">-5</span>
<span class="tag is-danger is-size-6 has-text-white"
>Poor</span
>
</div>
</td>
</tr>
</tbody>
</table> -->
<p>
Still under development. Please check back later for updates.
</p>
</div>
<div class="card-footer">
<a
href="#"
id="startFullScanBtn"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Start Full Scan
</a>
<a
href="#"
id="resetFullScanBtn"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div>
<div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">Full Neighbour Cell Scanner</div>
</div>
<div class="card-content">
<table class="table is-fullwidth" id="neighbourCellTable">
<thead>
<tr>
<th>Type</th>
<th>EARFCN</th>
<th>Physical ID</th>
<th class="is-hidden-mobile">RSRP</th>
<th class="is-hidden-mobile">RSRQ</th>
<th class="is-hidden-mobile">RSSI</th>
</tr>
</thead>
<tbody id="neighbourCellTableBody"></tbody>
</table>
</div>
<div class="card-footer">
<a
href="#"
id="startLTEScanBtn"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Start LTE Neighbourcell Scan
</a>
<a
href="#"
id="startNR5GScanBtn"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Start NR5G Neighbourcell Scan
</a>
<a
href="#"
id="resetScanBtn"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="content">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Full Network Provider Cell Scanner</span>
</div>
<p class="block has-text-weight-semibold">
This command is recommended to be used when there is no (U)SIM card.
<br />
This command does not apply to 5G cells in NSA mode.
<br />
Scanning will take a few minutes so please wait patiently.
</p>
</div>
</div>
</footer>
<div id="reboot-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do you want to reboot the device?
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">90</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">
<button class="button is-warning" id="rebootModem">Reboot</button>
<button class="button cancel" aria-label="close">Cancel</button>
</div>
</section>
</div>
</div>
</body>
</html>

View File

@@ -1,486 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!-- Logo -->
<link rel="simpleadmin-logo" href="favicon.ico" />
<link rel="stylesheet" href="css/bulma/bulma.scss" />
<link rel="stylesheet" href="css/bulma/css/bulma.min.css" />
<link rel="stylesheet" href="css/bulma/css/bulma.css" />
<link rel="stylesheet" href="css/custom.css" />
<!-- Font awesome icons -->
<script
src="https://kit.fontawesome.com/b0caedfab3.js"
crossorigin="anonymous"
></script>
<script src="js/styles/toggle-theme.js"></script>
<script src="/js/styles/nav-burger.js"></script>
<script src="/js/styles/modal-trigger.js"></script>
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script src="/js/cell-settings/fetch-settings.js"></script>
<script src="/js/cell-settings/apn-profile.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script>
(function () {
const savedTheme = localStorage.getItem("theme") || "theme-dark";
document.documentElement.classList.add(savedTheme);
})();
</script>
<title>QuecManager</title>
</head>
<body class="body-margin">
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/assets/logo.png" alt="Logo" />
<span class="title">QuecManager</span>
</a>
<a
role="button"
class="navbar-burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start ml-6">
<a class="navbar-item" href="/"> Home </a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link has-text-weight-bold"> Cellular </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/cell-settings.html"
>Cell Settings</a
>
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Advance </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/advance-settings.html">
Advance Settings
</a>
<a class="navbar-item" href="#">Experimental Features</a>
<a class="navbar-item" href="/cgi-bin/luci">OpenWRT Luci</a>
</div>
</div>
<a class="navbar-item" href="/about.html"> About </a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-flex-direction-column-mobile">
<div class="control is-expanded-mobile">
<div
id="restartConnectionBtn"
class="button is-link is-outlined is-fullwidth-mobile"
>
<span class="icon">
<i class="fas fa-arrows-rotate"></i>
</span>
<span>Restart Connection</span>
</div>
</div>
<div class="is-flex is-mobile is-align-items-center">
<div class="control">
<div
class="button is-warning is-outlined reboot-modal"
data-target="reboot-modal"
>
<span class="icon">
<i class="fas fa-power-off"></i>
</span>
</div>
</div>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
>
<span class="icon">
<i class="fas fa-sun"></i>
</span>
</a>
</p>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
id="logoutButton"
>
<span class="icon">
<i class="fas fa-right-from-bracket"></i>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="column-margin">
<div class="columns">
<div class="column">
<div class="card">
<div class="card-header">
<div class="card-header-title">Basic Cellular Settings</div>
</div>
<div class="card-content">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid is-gap-5">
<div class="cell">
<div class="field">
<label class="label">Current APN</label>
<div class="control">
<input
class="input"
type="text"
placeholder="Current APN Here"
id="currentAPN"
/>
</div>
<p class="help">
Changing this will disable automatic APN.
</p>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">APN PDP Type</label>
<p class="control has-icons-left">
<span class="select">
<select id="apnPDP">
<option selected>Select APN PDP Type</option>
<option value="IP">IPv4 Only</option>
<option value="IPV6">IPv6 Only</option>
<option value="IPV4V6">IPv4 and IPv6</option>
<option value="PPP">P2P Protocol</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-globe"></i>
</span>
</p>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">Preferred Network Mode</label>
<p class="control has-icons-left">
<span class="select">
<select id="networkPreference">
<option value="placeholder" selected>
Select Preferred Network Mode
</option>
<option value="AUTO">Automatic</option>
<option value="LTE">LTE Only</option>
<option value="NR5G">5G SA Only</option>
<option value="LTE:NR5G">5G NSA Only</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-signal"></i>
</span>
</p>
<p class="help">
Selecting a mode will apply immediately.
</p>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">NR5G Mode Control</label>
<p class="control has-icons-left">
<span class="select">
<select id="nr5gModeControl">
<option selected>Select NR5G Mode Control</option>
<option value="0">Enable NR5G SA and NSA</option>
<option value="2">Enable SA Only</option>
<option value="1">Enable NSA Only</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-podcast"></i>
</span>
</p>
<p class="help">
Selecting a mode will apply immediately.
</p>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">U-SIM Slot Configuration</label>
<p class="control has-icons-left">
<span class="select">
<select id="simSlot">
<option value="">Select active SIM slot</option>
<option value="1">SIM Slot 1</option>
<option value="2">SIM Slot 2</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-sim-card" id="simCardIcon"></i>
</span>
</p>
<p class="help">
Selecting a mode will apply immediately.
</p>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Save APN
</a>
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset APN
</a>
</div>
</div>
</div>
<div class="column">
<div class="card" id="apnProfileForm">
<div class="card-header">
<div class="card-header-title">APN and ICCID Based Locking</div>
</div>
<div class="card-content">
<div class="fixed-grid has-1-cols">
<div class="grid is-gap-5">
<div class="cell">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid is-gap-3">
<div class="cell is-col-span-2-mobile">
<div class="field">
<label class="label">APN Profile 1</label>
<div class="control">
<input
class="input"
type="text"
placeholder="APN Here"
id="apnProfile1"
/>
</div>
<p class="help">
This will override the current APN.
</p>
</div>
</div>
<div class="cell is-col-span-2-mobile">
<div class="field">
<label class="label">APN PDP Type</label>
<p class="control has-icons-left">
<span class="select">
<select id="apnPDPType1">
<option selected>Select APN PDP Type</option>
<option value="IP">IPv4 Only</option>
<option value="IPV6">IPv6 Only</option>
<option value="IPV4V6">IPv4 and IPv6</option>
<option value="PPP">P2P Protocol</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-globe"></i>
</span>
</p>
</div>
</div>
<div class="cell is-col-span-2">
<div class="field">
<label class="label">ICCID Profile 1</label>
<div class="control">
<input
class="input"
type="text"
placeholder="ICCID Here"
id="iccidProfile1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="cell">
<div class="fixed-grid has-2-cols">
<div class="grid is-gap-3">
<div class="cell is-col-span-2-mobile">
<div class="field">
<label class="label">APN Profile 2</label>
<div class="control">
<input
class="input"
type="text"
placeholder="APN Here"
id="apnProfile2"
/>
</div>
<p class="help">
This will override the current APN.
</p>
</div>
</div>
<div class="cell is-col-span-2-mobile">
<div class="field">
<label class="label">APN PDP Type</label>
<p class="control has-icons-left">
<span class="select">
<select id="apnPDPType2">
<option selected>Select APN PDP Type</option>
<option value="IP">IPv4 Only</option>
<option value="IPV6">IPv6 Only</option>
<option value="IPV4V6">IPv4 and IPv6</option>
<option value="PPP">P2P Protocol</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-globe"></i>
</span>
</p>
</div>
</div>
<div class="cell is-col-span-2">
<div class="field">
<label class="label">ICCID Profile 2</label>
<div class="control">
<input
class="input"
type="text"
placeholder="ICCID Here"
id="iccidProfile2"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
id="saveAPNProfile"
>
Save APN Profile
</a>
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
id="resetAPNProfile"
>
Reset APN Profile
</a>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="content">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid">
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Information</span>
</div>
<p class="block has-text-weight-semibold">
Changing APN disconnects and reconnects the network
automatically.
<br />
If problem persists after changing settings, please reboot the
modem.
<br />
Please use the settings with caution.
</p>
</div>
<div class="cell">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Information</span>
</div>
<p class="block has-text-weight-semibold">
APN and ICCID Based Locking will use a stored APN profile based
on the current SIM's ICCID.
<br />
Currently experimental.
<br />
</p>
</div>
</div>
</div>
</div>
</footer>
<div id="reboot-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do you want to reboot the device?
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">90</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">
<button class="button is-warning" id="rebootModem">Reboot</button>
<button class="button cancel" aria-label="close">Cancel</button>
</div>
</section>
</div>
</div>
</body>
</html>

View File

@@ -1,286 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!-- Logo -->
<link rel="simpleadmin-logo" href="favicon.ico" />
<link rel="stylesheet" href="css/bulma/bulma.scss" />
<link rel="stylesheet" href="css/bulma/css/bulma.min.css" />
<link rel="stylesheet" href="css/bulma/css/bulma.css" />
<link rel="stylesheet" href="css/custom.css" />
<!-- Font awesome icons -->
<script
src="https://kit.fontawesome.com/b0caedfab3.js"
crossorigin="anonymous"
></script>
<script src="js/styles/toggle-theme.js"></script>
<script src="/js/styles/nav-burger.js"></script>
<script src="/js/styles/modal-trigger.js"></script>
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script src="/js/cell-sms/sms-manager.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script>
(function () {
const savedTheme = localStorage.getItem("theme") || "theme-dark";
document.documentElement.classList.add(savedTheme);
})();
</script>
<title>QuecManager</title>
</head>
<body class="body-margin">
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/assets/logo.png" alt="Logo" />
<span class="title">QuecManager</span>
</a>
<a
role="button"
class="navbar-burger"
aria-label="menu"
aria-expanded="false"
data-target="navMenu"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start ml-6">
<a class="navbar-item" href="/"> Home </a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link has-text-weight-bold"> Cellular </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/cell-settings.html"
>Cell Settings</a
>
<a class="navbar-item" href="/bandlock.html"> Band Locking </a>
<a class="navbar-item" href="/cell-locking.html">Cell Locking</a>
<a class="navbar-item" href="/cell-scanner.html">Cell Scanner</a>
<a class="navbar-item" href="/cell-sms.html"> Cell SMS </a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link"> Advance </a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/advance-settings.html">
Advance Settings
</a>
<a class="navbar-item" href="#">Experimental Features</a>
<a class="navbar-item" href="/cgi-bin/luci">OpenWRT Luci</a>
</div>
</div>
<a class="navbar-item" href="/about.html"> About </a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-flex-direction-column-mobile">
<div class="control is-expanded-mobile">
<div
id="restartConnectionBtn"
class="button is-link is-outlined is-fullwidth-mobile"
>
<span class="icon">
<i class="fas fa-arrows-rotate"></i>
</span>
<span>Restart Connection</span>
</div>
</div>
<div class="is-flex is-mobile is-align-items-center">
<div class="control">
<div
class="button is-warning is-outlined reboot-modal"
data-target="reboot-modal"
>
<span class="icon">
<i class="fas fa-power-off"></i>
</span>
</div>
</div>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
>
<span class="icon">
<i class="fas fa-sun"></i>
</span>
</a>
</p>
<p class="control ml-2 is-mobile">
<a
href="#"
class="button is-warning is-outlined js-theme-toggle"
id="logoutButton"
>
<span class="icon">
<i class="fas fa-right-from-bracket"></i>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="column-margin">
<div class="fixed-grid has-1-cols">
<div class="grid is-gap-5">
<div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">SMS Inbox</div>
</div>
<div class="card-content">
<div
class="fixed-grid has-1-cols"
style="height: 450px; overflow-y: scroll"
>
<!-- This is where messages will be inserted -->
<div id="sms-container" class="grid is-gap-4 is-fullwidth">
<!-- Messages will be populated here -->
</div>
</div>
</div>
<div class="card-footer">
<a
href="#"
id="refresh-sms"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Refresh
</a>
<a
href="#"
id="delete-selected-sms"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Delete Selected
</a>
</div>
</div>
</div>
<div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">Send SMS</div>
</div>
<div class="card-content">
<div class="fixed-grid has-5-cols has-1-cols-mobile">
<div class="grid">
<div class="cell is-col-span-1">
<div class="field">
<label class="label">Recipient's Phone Number</label>
<div class="control has-icons-left">
<input
id="phone-number-input"
class="input"
type="text"
placeholder="Input Phone Number"
/>
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>
</div>
</div>
</div>
<div class="cell is-col-span-5 is-col-span-1-mobile">
<div class="field">
<label class="label">Message</label>
<div class="control">
<textarea
id="message-input"
class="textarea"
placeholder="Enter your message here"
></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<a
href="#"
id="send-sms"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Send SMS
</a>
<a
href="#"
id="reset-form"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="content">
<div class="is-flex is-flex-direction-column is-align-items-center">
<div class="has-text-centered">
<div class="icon-text">
<span class="icon has-text-info">
<i class="fas fa-info-circle"></i>
</span>
<span>Information</span>
</div>
<p class="block has-text-weight-semibold">
This is an experimental feature and may cause an error in some
cases.
</p>
</div>
</div>
</div>
</footer>
<div id="reboot-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do you want to reboot the device?
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>
<div class="countdown-text">
Rebooting... <span id="countdown">90</span>s
</div>
</div>
<div class="buttons" id="modal-buttons">
<button class="button is-warning" id="rebootModem">Reboot</button>
<button class="button cancel" aria-label="close">Cancel</button>
</div>
</section>
</div>
</div>
</body>
</html>

View File

@@ -1,66 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+CGMI' 'AT+CGMM' 'AT+CGMR' 'AT+CNUM' 'AT+CIMI' 'AT+ICCID' 'AT+CGSN' 'AT+QMAP="LANIP"' 'AT+QMAP="WWAN"' 'AT+QGETCAPABILITY'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -1,66 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+QMAP="MPDN_RULE"' 'AT+QMAP="DHCPV4DNS"' 'AT+QCFG="usbnet"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -0,0 +1,26 @@
#!/bin/sh
# Set content type for JSON response
echo "Content-Type: application/json"
echo ""
# Check if the file exists
if [ -f "/etc/config/atcommands.user" ]; then
# Start JSON object
printf "{\n"
awk -F';' '
BEGIN { first = 1 }
{
gsub(/\r/, "", $0)
if (!first) printf ",\n "
else printf " "
gsub(/"/, "\\\"", $1)
gsub(/"/, "\\\"", $2)
printf "\"%s\": \"%s\"", $1, $2
first = 0
}
' /etc/config/atcommands.user
printf "\n}"
else
echo '{"error": "No Data"}'
fi

View File

@@ -0,0 +1,90 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
mtu_firewall_file="/etc/firewall.user.mtu"
network_interface="rmnet_data0"
lan_utils_script="/etc/data/lanUtils.sh"
get_current_mtu() {
ip link show "$network_interface" | grep -o "mtu [0-9]*" | cut -d' ' -f2
}
update_lanutils_mtu_config() {
local action="$1"
if [ "$action" = "add" ]; then
# Add the MTU firewall file line if not already present
if ! grep -q "local mtu_firewall_file=/etc/firewall.user.mtu" "$lan_utils_script"; then
sed -i '/local ttl_firewall_file=\/etc\/firewall.user.ttl/a local mtu_firewall_file=/etc/firewall.user.mtu' "$lan_utils_script"
fi
elif [ "$action" = "remove" ]; then
# Remove the MTU firewall file line if present
sed -i '/local mtu_firewall_file=\/etc\/firewall.user.mtu/d' "$lan_utils_script"
fi
}
case "$REQUEST_METHOD" in
GET)
# Fetch current MTU
current_mtu=$(get_current_mtu)
current_mtu=${current_mtu:-1500}
# Check if custom MTU is configured
if [ -f "$mtu_firewall_file" ]; then
echo "{\"isEnabled\": true, \"currentValue\": $current_mtu}"
else
echo "{\"isEnabled\": false, \"currentValue\": $current_mtu}"
fi
;;
POST)
read -r post_data
mtu_value=$(echo "$post_data" | sed 's/mtu=//')
# Check for disable functionality
if [ "$mtu_value" = "disable" ]; then
# Remove the MTU configuration file
rm -f "$mtu_firewall_file"
# Remove the MTU configuration line from lanUtils.sh
update_lanutils_mtu_config "remove"
# Get the default MTU
default_mtu=$(get_current_mtu)
default_mtu=${default_mtu:-1500}
echo "{\"success\": true, \"message\": \"MTU configuration disabled\", \"currentValue\": $default_mtu}"
exit 0
fi
# Validate MTU input
if ! [[ "$mtu_value" =~ ^[0-9]+$ ]]; then
echo "{\"success\": false, \"error\": \"Invalid MTU value\"}"
exit 1
fi
# Create firewall MTU configuration file with individual interface commands
> "$mtu_firewall_file" # Clear the file
for iface in $(ls /sys/class/net | grep '^rmnet_data'); do
echo "ip link set $iface mtu $mtu_value" >> "$mtu_firewall_file"
done
# Immediately apply MTU change
for iface in $(ls /sys/class/net | grep '^rmnet_data'); do
ip link set "$iface" mtu "$mtu_value"
done
# Add the MTU configuration line to lanUtils.sh
update_lanutils_mtu_config "add"
# Run lanUtils.sh to update network configuration
if [ -f "$lan_utils_script" ]; then
. "$lan_utils_script"
fi
echo "{\"success\": true, \"message\": \"MTU configuration updated to $mtu_value\", \"currentValue\": $mtu_value}"
;;
*)
echo "{\"success\": false, \"error\": \"Invalid request method\"}"
;;
esac

View File

@@ -1,66 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+QMAP="MPDN_RULE"' 'AT+QMAP="DHCPV4DNS"' 'AT+QCFG="usbnet"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -1,153 +0,0 @@
#!/bin/sh
# Parse POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | grep -o 'iccidProfile1=[^&]*' | cut -d= -f2)
apnProfile1=$(echo "$QUERY_STRING" | grep -o 'apnProfile1=[^&]*' | cut -d= -f2)
pdpType1=$(echo "$QUERY_STRING" | grep -o 'pdpType1=[^&]*' | cut -d= -f2)
iccidProfile2=$(echo "$QUERY_STRING" | grep -o 'iccidProfile2=[^&]*' | cut -d= -f2)
apnProfile2=$(echo "$QUERY_STRING" | grep -o 'apnProfile2=[^&]*' | cut -d= -f2)
pdpType2=$(echo "$QUERY_STRING" | grep -o 'pdpType2=[^&]*' | cut -d= -f2)
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
apnProfile1=$(urldecode "$apnProfile1")
pdpType1=$(urldecode "$pdpType1")
iccidProfile2=$(urldecode "$iccidProfile2")
apnProfile2=$(urldecode "$apnProfile2")
pdpType2=$(urldecode "$pdpType2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Create the directory structure
mkdir -p /etc/quecmanager
# Create a configuration file to store APN profiles (as plain text)
cat > /etc/quecmanager/apn_config.txt << EOF
iccidProfile1=$iccidProfile1
apnProfile1=$apnProfile1
pdpType1=$pdpType1
EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >> /etc/quecmanager/apn_config.txt << EOF
iccidProfile2=$iccidProfile2
apnProfile2=$apnProfile2
pdpType2=$pdpType2
EOF
fi
# Create the apnProfiles.sh script
cat > /etc/quecmanager/apnProfiles.sh << 'EOF'
#!/bin/sh
# Function to read config values
get_config_value() {
local key=$1
grep "^${key}=" /etc/quecmanager/apn_config.txt | cut -d'=' -f2
}
# Read configuration
iccidProfile1=$(get_config_value "iccidProfile1")
apnProfile1=$(get_config_value "apnProfile1")
pdpType1=$(get_config_value "pdpType1")
iccidProfile2=$(get_config_value "iccidProfile2")
apnProfile2=$(get_config_value "apnProfile2")
pdpType2=$(get_config_value "pdpType2")
# Function to get current ICCID
get_current_iccid() {
local input_file="/tmp/inputICCID.txt"
local output_file="/tmp/outputICCID.txt"
echo "AT+ICCID" > "$input_file"
atinout "$input_file" /dev/smd11 "$output_file"
iccid=$(cat "$output_file" | grep "+ICCID:" | cut -d' ' -f2)
rm -f "$input_file" "$output_file"
echo "$iccid"
}
# Function to set APN
set_apn() {
local pdp_type="$1"
local apn="$2"
local input_file="/tmp/inputAPN.txt"
local output_file="/tmp/outputAPN.txt"
echo "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0" > "$input_file"
atinout "$input_file" /dev/smd11 "$output_file"
local result=$(cat "$output_file")
rm -f "$input_file" "$output_file"
if echo "$result" | grep -q "OK"; then
return 0
else
return 1
fi
}
# Get current ICCID
current_iccid=$(get_current_iccid)
success=false
# Check ICCID against profile 1 (required)
if [ "$current_iccid" = "$iccidProfile1" ]; then
if set_apn "$pdpType1" "$apnProfile1"; then
success=true
fi
# Check ICCID against profile 2 (optional)
elif [ -n "$iccidProfile2" ] && [ "$current_iccid" = "$iccidProfile2" ]; then
if set_apn "$pdpType2" "$apnProfile2"; then
success=true
fi
fi
if [ "$success" = "true" ]; then
echo "APN set successfully" > /tmp/apn_result.txt
else
echo "Failed to set APN" > /tmp/apn_result.txt
fi
EOF
# Make the script executable
chmod +x /etc/quecmanager/apnProfiles.sh
# Add to rc.local if not already present
if ! grep -q "/etc/quecmanager/apnProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/apnProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/apnProfiles.sh
# Check the result
if [ -f /tmp/apn_result.txt ]; then
result=$(cat /tmp/apn_result.txt)
rm -f /tmp/apn_result.txt
if [ "$result" = "APN set successfully" ]; then
echo '{"status": "success", "message": "APN profiles saved and applied successfully"}'
else
echo '{"status": "error", "message": "APN profiles saved but failed to apply"}'
fi
else
echo '{"status": "error", "message": "Something went wrong while processing APN profiles"}'
fi

View File

@@ -22,13 +22,48 @@ COMMAND=$(urldecode "$RAW_COMMAND")
# Define unique input/output files and AT port
INPUT_FILE="/tmp/custom_input_$$.txt"
OUTPUT_FILE="/tmp/custom_output_$$.txt"
AT_PORT="/dev/smd7"
# Debug logging
DEBUG_LOG="/tmp/debug.log"
echo "Starting at_handler script at $(date)" > "$DEBUG_LOG"
CONFIG_FILE="/etc/quecManager.conf"
# Check config file
if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file not found: $CONFIG_FILE" >> "$DEBUG_LOG"
echo '{"error": "Config file not found"}'
exit 1
fi
# Get AT_PORT with debug logging
# Get AT_PORT with debug logging
AT_PORT=$(head -n 2 "$CONFIG_FILE" | tail -n 1 | cut -d'=' -f2 | tr -d ' \n\r' | sed 's|^dev/||')
echo "Raw config line: $(head -n 1 "$CONFIG_FILE")" >> "$DEBUG_LOG"
echo "Extracted AT_PORT: '$AT_PORT'" >> "$DEBUG_LOG"
# List available devices for debugging
ls -l /dev/smd* >> "$DEBUG_LOG" 2>&1
if [ -z "$AT_PORT" ]; then
echo "AT_PORT is empty" >> "$DEBUG_LOG"
echo '{"error": "Failed to read AT_PORT from config"}'
exit 1
fi
# Check if AT_PORT exists
if [ ! -c "/dev/$AT_PORT" ]; then
echo "AT_PORT device not found: /dev/$AT_PORT" >> "$DEBUG_LOG"
echo "Available smd devices:" >> "$DEBUG_LOG"
ls -l /dev/smd* >> "$DEBUG_LOG" 2>&1
echo '{"error": "AT_PORT device not found"}'
exit 1
fi
# Write the command directly to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
atinout "$INPUT_FILE" "/dev/$AT_PORT" "$OUTPUT_FILE"
# Read the output from output.txt
OUTPUT=$(cat "$OUTPUT_FILE")

View File

@@ -7,6 +7,9 @@ echo ""
# Read POST data
read POST_DATA
# Debug log for generated hash
DEBUG_LOG = "/tmp/auth.log"
# Extract the password from POST data (URL encoded)
USER="root"
INPUT_PASSWORD=$(echo "$POST_DATA" | sed -n 's/^.*password=\([^&]*\).*$/\1/p')
@@ -14,9 +17,6 @@ INPUT_PASSWORD=$(echo "$POST_DATA" | sed -n 's/^.*password=\([^&]*\).*$/\1/p')
# URL-decode the password (replace + with space and decode %XX)
INPUT_PASSWORD=$(echo "$INPUT_PASSWORD" | sed 's/+/ /g;s/%\(..\)/\\x\1/g' | xargs -0 printf "%b")
# Log received password for debugging (remove in production)
# echo "Received password: $INPUT_PASSWORD" >&2
# Extract the hashed password from /etc/shadow for the specified user
USER_SHADOW_ENTRY=$(grep "^$USER:" /etc/shadow)
@@ -35,11 +35,11 @@ SALT=$(echo "$USER_HASH" | cut -d'$' -f3)
GENERATED_HASH=$(echo "$INPUT_PASSWORD" | openssl passwd -1 -salt "$SALT" -stdin)
# Log generated hash for debugging
echo "Generated hash: $GENERATED_HASH" >&2
echo "Generated hash: $GENERATED_HASH" >> $DEBUG_LOG
# Compare the generated hash with the one in the shadow file
if [ "$GENERATED_HASH" = "$USER_HASH" ]; then
echo '{"state":"success", "hashed_password":"'"$GENERATED_HASH"'"}'
echo '{"state":"success"}'
else
echo '{"state":"failed", "hashed_password":"'"$GENERATED_HASH"'"}'
echo '{"state":"failed"}'
fi

View File

@@ -1,258 +0,0 @@
#!/bin/sh
# Parse POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Function to send AT commands silently
send_at_command() {
echo "$1" | atinout - /dev/smd7 - >/dev/null 2>&1
}
# Extract reset flags
reset_lte=$(echo "$QUERY_STRING" | grep -o 'reset_lte=[^&]*' | cut -d= -f2)
reset_5g=$(echo "$QUERY_STRING" | grep -o 'reset_5g=[^&]*' | cut -d= -f2)
# Extract LTE values from POST data
earfcn1=$(echo "$QUERY_STRING" | grep -o 'earfcn1=[^&]*' | cut -d= -f2)
pci1=$(echo "$QUERY_STRING" | grep -o 'pci1=[^&]*' | cut -d= -f2)
earfcn2=$(echo "$QUERY_STRING" | grep -o 'earfcn2=[^&]*' | cut -d= -f2)
pci2=$(echo "$QUERY_STRING" | grep -o 'pci2=[^&]*' | cut -d= -f2)
earfcn3=$(echo "$QUERY_STRING" | grep -o 'earfcn3=[^&]*' | cut -d= -f2)
pci3=$(echo "$QUERY_STRING" | grep -o 'pci3=[^&]*' | cut -d= -f2)
# Extract 5G-SA values from POST data
nrarfcn=$(echo "$QUERY_STRING" | grep -o 'nrarfcn=[^&]*' | cut -d= -f2)
nrpci=$(echo "$QUERY_STRING" | grep -o 'nrpci=[^&]*' | cut -d= -f2)
scs=$(echo "$QUERY_STRING" | grep -o 'scs=[^&]*' | cut -d= -f2)
band=$(echo "$QUERY_STRING" | grep -o 'band=[^&]*' | cut -d= -f2)
# URL decode all values
reset_lte=$(urldecode "$reset_lte")
reset_5g=$(urldecode "$reset_5g")
earfcn1=$(urldecode "$earfcn1")
pci1=$(urldecode "$pci1")
earfcn2=$(urldecode "$earfcn2")
pci2=$(urldecode "$pci2")
earfcn3=$(urldecode "$earfcn3")
pci3=$(urldecode "$pci3")
nrarfcn=$(urldecode "$nrarfcn")
nrpci=$(urldecode "$nrpci")
scs=$(urldecode "$scs")
band=$(urldecode "$band")
# Send Content-type header before any other output
echo "Content-type: application/json"
echo ""
# Handle reset requests
if [ "$reset_lte" = "1" ] || [ "$reset_5g" = "1" ]; then
# Remove configuration files
rm -f /etc/quecmanager/cell_lock_config.txt
rm -f /etc/quecmanager/apply_cell_lock.sh
# Remove from rc.local if present
sed -i '/\/etc\/quecmanager\/apply_cell_lock.sh/d' /etc/rc.local
if [ "$reset_lte" = "1" ] && [ "$reset_5g" = "1" ]; then
send_at_command "AT+QNWLOCK=\"common/4g\",0"
send_at_command "AT+QNWLOCK=\"common/5g\",0"
send_at_command "AT+QNWPREFCFG=\"mode_pref\",AUTO"
sleep 1
send_at_command "AT+COPS=2"
sleep 1
send_at_command "AT+COPS=0"
echo '{"status": "success", "message": "All cell lock configurations removed"}'
elif [ "$reset_lte" = "1" ]; then
send_at_command "AT+QNWLOCK=\"common/4g\",0"
sleep 1
send_at_command "AT+COPS=2"
sleep 1
send_at_command "AT+COPS=0"
echo '{"status": "success", "message": "LTE cell lock configuration removed"}'
else
send_at_command "AT+QNWLOCK=\"common/5g\",0"
send_at_command "AT+QNWPREFCFG=\"mode_pref\",AUTO"
sleep 1
send_at_command "AT+COPS=2"
sleep 1
send_at_command "AT+COPS=0"
echo '{"status": "success", "message": "5G cell lock configuration removed"}'
fi
exit 0
fi
# Create the directory structure if it doesn't exist
mkdir -p /etc/quecmanager /var/log/quecmanager
# Create a configuration file to store cell locking profiles
cat >/etc/quecmanager/cell_lock_config.txt <<EOF
# LTE Cell Locking Configuration
earfcn1=$earfcn1
pci1=$pci1
earfcn2=$earfcn2
pci2=$pci2
earfcn3=$earfcn3
pci3=$pci3
# 5G-SA Cell Locking Configuration
nrarfcn=$nrarfcn
nrpci=$nrpci
scs=$scs
band=$band
EOF
# Create the apply_cell_lock.sh script
cat >/etc/quecmanager/apply_cell_lock.sh <<'EOF'
#!/bin/sh
# Create log directory if it doesn't exist
LOG_DIR="/var/log/quecmanager"
mkdir -p "$LOG_DIR"
DEBUG_LOG="$LOG_DIR/cell_lock_debug.log"
# Function to log messages
log_message() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "$timestamp - $message" >> "$DEBUG_LOG"
}
# Verify required tools
if ! command -v atinout >/dev/null 2>&1; then
log_message "Error: atinout command not found"
exit 1
fi
if [ ! -c "/dev/smd7" ]; then
log_message "Error: Modem device /dev/smd7 not found"
exit 1
fi
# Function to send AT commands
send_at_command() {
local command="$1"
local description="$2"
local retry_count=0
local max_retries=3
log_message "Attempting to send command: $command ($description)"
while [ $retry_count -lt $max_retries ]; do
echo "$command" | atinout - /dev/smd7 - > /tmp/at_response.txt 2>&1
local result=$(cat /tmp/at_response.txt)
log_message "Attempt $((retry_count + 1)) - Response: $result"
if echo "$result" | grep -q "OK"; then
log_message "Command successful: $description"
return 0
fi
retry_count=$((retry_count + 1))
log_message "Command failed, retry $retry_count of $max_retries"
sleep 2
done
log_message "Command failed after $max_retries retries: $description"
return 1
}
# Function to apply cell lock configuration
apply_cell_lock() {
local config_file="/etc/quecmanager/cell_lock_config.txt"
if [ ! -f "$config_file" ]; then
log_message "Configuration file not found"
return 1
fi
# Read configuration values
. "$config_file"
# Test modem responsiveness
if ! send_at_command "AT" "Testing modem responsiveness"; then
return 1
fi
# Apply LTE configuration if present
if [ -n "$earfcn1" ] && [ -n "$pci1" ]; then
if [ -n "$earfcn2" ] && [ -n "$pci2" ]; then
if [ -n "$earfcn3" ] && [ -n "$pci3" ]; then
send_at_command "AT+QNWLOCK=\"common/4g\",3,$earfcn1,$pci1,$earfcn2,$pci2,$earfcn3,$pci3" "Setting LTE lock (3 cells)"
else
send_at_command "AT+QNWLOCK=\"common/4g\",2,$earfcn1,$pci1,$earfcn2,$pci2" "Setting LTE lock (2 cells)"
fi
else
send_at_command "AT+QNWLOCK=\"common/4g\",1,$earfcn1,$pci1" "Setting LTE lock (1 cell)"
fi
sleep 1
if ! send_at_command "AT+COPS=2" "Network Disconnected"; then
return 1
fi
sleep 1
if ! send_at_command "AT+COPS=0" "Network Reconnected"; then
return 1
fi
fi
# Apply 5G configuration if present
if [ -n "$nrpci" ] && [ -n "$nrarfcn" ] && [ -n "$scs" ] && [ -n "$band" ]; then
if ! send_at_command "AT+QNWPREFCFG=\"mode_pref\",NR5G" "Setting network to SA only"; then
return 1
fi
sleep 1
if ! send_at_command "AT+QNWLOCK=\"common/5g\",$nrpci,$nrarfcn,$scs,$band" "Setting 5G lock"; then
return 1
fi
sleep 1
if ! send_at_command "AT+COPS=2" "Network Disconnected"; then
return 1
fi
sleep 1
if ! send_at_command "AT+COPS=0" "Network Reconnected"; then
return 1
fi
fi
return 0
}
# Main execution
log_message "Starting cell lock configuration"
if apply_cell_lock; then
log_message "Cell lock configuration applied successfully"
exit 0
else
log_message "Failed to apply cell lock configuration"
exit 1
fi
EOF
# Make the script executable
chmod +x /etc/quecmanager/apply_cell_lock.sh
# Add to rc.local if not already present
if ! grep -q "/etc/quecmanager/apply_cell_lock.sh" /etc/rc.local; then
sed -i '/exit 0/i sleep 30\n\/etc\/quecmanager\/apply_cell_lock.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/apply_cell_lock.sh
result=$?
if [ $result -eq 0 ]; then
echo '{"status": "success", "message": "Cell lock configurations saved and applied successfully"}'
else
echo '{"status": "error", "message": "Cell lock configurations saved but failed to apply"}'
fi

View File

@@ -1,60 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/cell_lock_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"status": "error", "message": "No cell lock configurations found", "configurations": {}}'
exit 0
fi
# Function to read config values
get_config_value() {
local key=$1
local value=$(grep "^$key=" "$CONFIG_FILE" | sed "s/^$key=//")
# Remove any trailing whitespace or comments
value=$(echo "$value" | sed 's/[[:space:]]*#.*$//' | sed 's/[[:space:]]*$//')
echo "$value"
}
# Read LTE configuration values
earfcn1=$(get_config_value "earfcn1")
pci1=$(get_config_value "pci1")
earfcn2=$(get_config_value "earfcn2")
pci2=$(get_config_value "pci2")
earfcn3=$(get_config_value "earfcn3")
pci3=$(get_config_value "pci3")
# Read 5G-SA configuration values
nrarfcn=$(get_config_value "nrarfcn")
nrpci=$(get_config_value "nrpci")
scs=$(get_config_value "scs")
band=$(get_config_value "band")
# Debug output to syslog
logger "fetch-cell-lock: earfcn1=$earfcn1 pci1=$pci1 nrarfcn=$nrarfcn nrpci=$nrpci"
# Construct JSON response
cat << EOF
{
"status": "success",
"configurations": {
"lte": {
"earfcn1": "${earfcn1:-}",
"pci1": "${pci1:-}",
"earfcn2": "${earfcn2:-}",
"pci2": "${pci2:-}",
"earfcn3": "${earfcn3:-}",
"pci3": "${pci3:-}"
},
"sa": {
"nrarfcn": "${nrarfcn:-}",
"nrpci": "${nrpci:-}",
"scs": "${scs:-}",
"band": "${band:-}"
}
}
}
EOF

View File

@@ -1,120 +0,0 @@
#!/bin/sh
# Enable debug logging
# exec 1> >(logger -s -t $(basename $0)) 2>&1
# Create log directory if it doesn't exist
LOG_DIR="/var/log/quecmanager"
mkdir -p "$LOG_DIR"
DEBUG_LOG="$LOG_DIR/cell_lock_debug.log"
# Function to log messages
log_message() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "$timestamp - $message" >> "$DEBUG_LOG"
}
# Verify required tools
if ! command -v atinout >/dev/null 2>&1; then
log_message "Error: atinout command not found"
exit 1
fi
if [ ! -c "/dev/smd11" ]; then
log_message "Error: Modem device /dev/smd11 not found"
exit 1
fi
# Function to send AT commands
send_at_command() {
local command="$1"
local description="$2"
local retry_count=0
local max_retries=3
log_message "Attempting to send command: $command ($description)"
while [ $retry_count -lt $max_retries ]; do
echo "$command" | atinout - /dev/smd11 - > /tmp/at_response.txt 2>&1
local result=$(cat /tmp/at_response.txt)
log_message "Attempt $((retry_count + 1)) - Response: $result"
if echo "$result" | grep -q "OK"; then
log_message "Command successful: $description"
return 0
fi
retry_count=$((retry_count + 1))
log_message "Command failed, retry $retry_count of $max_retries"
sleep 2
done
log_message "Command failed after $max_retries retries: $description"
return 1
}
# Function to apply cell lock configuration
apply_cell_lock() {
local config_file="/etc/quecmanager/cell_lock_config.txt"
if [ ! -f "$config_file" ]; then
log_message "Configuration file not found"
return 1
fi
# Read configuration values
. "$config_file"
# Test modem responsiveness
if ! send_at_command "AT" "Testing modem responsiveness"; then
return 1
fi
# Apply LTE configuration if present
if [ -n "$earfcn1" ] && [ -n "$pci1" ]; then
if ! send_at_command "AT+CFUN=0" "Setting radio off"; then
return 1
fi
sleep 2
if [ -n "$earfcn2" ] && [ -n "$pci2" ]; then
if [ -n "$earfcn3" ] && [ -n "$pci3" ]; then
send_at_command "AT+QNWLOCK=\"common/4g\",3,$earfcn1,$pci1,$earfcn2,$pci2,$earfcn3,$pci3" "Setting LTE lock (3 cells)"
else
send_at_command "AT+QNWLOCK=\"common/4g\",2,$earfcn1,$pci1,$earfcn2,$pci2" "Setting LTE lock (2 cells)"
fi
else
send_at_command "AT+QNWLOCK=\"common/4g\",1,$earfcn1,$pci1" "Setting LTE lock (1 cell)"
fi
sleep 2
if ! send_at_command "AT+CFUN=1" "Setting radio on"; then
return 1
fi
fi
# Apply 5G configuration if present
if [ -n "$nrpci" ] && [ -n "$nrarfcn" ] && [ -n "$scs" ] && [ -n "$band" ]; then
if ! send_at_command "AT+CFUN=0" "Setting radio off"; then
return 1
fi
sleep 2
if ! send_at_command "AT+QNWLOCK=\"common/5g\",$nrpci,$nrarfcn,$scs,$band" "Setting 5G lock"; then
return 1
fi
sleep 2
if ! send_at_command "AT+CFUN=1" "Setting radio on"; then
return 1
fi
fi
}
# Main execution
log_message "Starting cell lock configuration"
if apply_cell_lock; then
log_message "Cell lock configuration applied successfully"
exit 0
else
log_message "Failed to apply cell lock configuration"
exit 1
fi

View File

@@ -1,66 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+CGDCONT?' 'AT+QNWPREFCFG="mode_pref"' 'AT+QNWPREFCFG="nr5g_disable_mode"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -0,0 +1,66 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error flag
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Remove the entire quecmanager directory
if [ -d "/etc/quecmanager/apn_profile/" ]; then
rm -rf /etc/quecmanager/apn_profile/
if [ $? -ne 0 ]; then
append_error "Failed to remove quecmanager directory"
fi
else
append_error "quecmanager directory not found"
fi
# Remove the line from rc.local
if [ -f "/etc/rc.local" ]; then
# Create a temporary file
temp_file=$(mktemp)
# Remove the apnProfiles.sh line and copy to temp file
sed '/\/etc\/quecmanager\/apnProfiles.sh/d' /etc/rc.local > "$temp_file"
# Check if sed command was successful
if [ $? -eq 0 ]; then
# Replace original file with modified version
mv "$temp_file" /etc/rc.local
if [ $? -ne 0 ]; then
append_error "Failed to update rc.local"
fi
else
append_error "Failed to modify rc.local"
rm -f "$temp_file"
fi
else
append_error "rc.local file not found"
fi
# Remove temporary files that might have been created
rm -f /tmp/apn_result.txt
rm -f /tmp/debug.log
rm -f /tmp/inputICCID.txt
rm -f /tmp/outputICCID.txt
rm -f /tmp/inputAPN.txt
rm -f /tmp/outputAPN.txt
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"APN profiles and configuration successfully removed\"}"
fi

View File

@@ -0,0 +1,45 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/apn_profile/apn_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo "{}"
exit 0
fi
# Read the configuration file
iccidProfile1=$(grep "^iccidProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
apnProfile1=$(grep "^apnProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
pdpType1=$(grep "^pdpType1=" "$CONFIG_FILE" | cut -d'=' -f2)
iccidProfile2=$(grep "^iccidProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
apnProfile2=$(grep "^apnProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
pdpType2=$(grep "^pdpType2=" "$CONFIG_FILE" | cut -d'=' -f2)
# Build the JSON response
echo "{"
# Add Profile 1 if it exists
if [ -n "$iccidProfile1" ]; then
echo " \"profile1\": {"
echo " \"iccid\": \"$iccidProfile1\","
echo " \"apn\": \"$apnProfile1\","
echo " \"pdpType\": \"$pdpType1\""
echo " }"
# Add comma if Profile 2 exists
[ -n "$iccidProfile2" ] && echo " ,"
fi
# Add Profile 2 if it exists
if [ -n "$iccidProfile2" ]; then
echo " \"profile2\": {"
echo " \"iccid\": \"$iccidProfile2\","
echo " \"apn\": \"$apnProfile2\","
echo " \"pdpType\": \"$pdpType2\""
echo " }"
fi
echo "}"

View File

@@ -33,11 +33,12 @@ if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
exit 1
fi
# Create the directory structure
mkdir -p /etc/quecmanager
if [ ! -d /etc/quecmanager/apn_profile ]; then
mkdir -p /etc/quecmanager/apn_profile
fi
# Create a configuration file to store APN profiles (as plain text)
cat > /etc/quecmanager/apn_config.txt << EOF
cat > /etc/quecmanager/apn_profile/apn_config.txt << EOF
iccidProfile1=$iccidProfile1
apnProfile1=$apnProfile1
pdpType1=$pdpType1
@@ -45,7 +46,7 @@ EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >> /etc/quecmanager/apn_config.txt << EOF
cat >> /etc/quecmanager/apn_profile/apn_config.txt << EOF
iccidProfile2=$iccidProfile2
apnProfile2=$apnProfile2
pdpType2=$pdpType2
@@ -53,13 +54,13 @@ EOF
fi
# Create the apnProfiles.sh script
cat > /etc/quecmanager/apnProfiles.sh << 'EOF'
cat > /etc/quecmanager/apn_profile/apnProfiles.sh << 'EOF'
#!/bin/sh
# Function to read config values
get_config_value() {
local key=$1
grep "^${key}=" /etc/quecmanager/apn_config.txt | cut -d'=' -f2
grep "^${key}=" /etc/quecmanager/apn_profile/apn_config.txt | cut -d'=' -f2
}
# Read configuration
@@ -70,13 +71,48 @@ iccidProfile2=$(get_config_value "iccidProfile2")
apnProfile2=$(get_config_value "apnProfile2")
pdpType2=$(get_config_value "pdpType2")
# Debug logging
DEBUG_LOG="/tmp/debug.log"
echo "Starting script at $(date)" > "$DEBUG_LOG"
CONFIG_FILE="/etc/quecManager.conf"
# Check config file
if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file not found: $CONFIG_FILE" >> "$DEBUG_LOG"
echo '{"error": "Config file not found"}'
exit 1
fi
# Get AT_PORT with debug logging
AT_PORT=$(head -n 1 "$CONFIG_FILE" | cut -d'=' -f2 | tr -d ' \n\r' | sed 's|^dev/||')
echo "Raw config line: $(head -n 1 "$CONFIG_FILE")" >> "$DEBUG_LOG"
echo "Extracted AT_PORT: '$AT_PORT'" >> "$DEBUG_LOG"
# List available devices for debugging
ls -l /dev/smd* >> "$DEBUG_LOG" 2>&1
if [ -z "$AT_PORT" ]; then
echo "AT_PORT is empty" >> "$DEBUG_LOG"
echo '{"error": "Failed to read AT_PORT from config"}'
exit 1
fi
# Check if AT_PORT exists
if [ ! -c "/dev/$AT_PORT" ]; then
echo "AT_PORT device not found: /dev/$AT_PORT" >> "$DEBUG_LOG"
echo "Available smd devices:" >> "$DEBUG_LOG"
ls -l /dev/smd* >> "$DEBUG_LOG" 2>&1
echo '{"error": "AT_PORT device not found"}'
exit 1
fi
# Function to get current ICCID
get_current_iccid() {
local input_file="/tmp/inputICCID.txt"
local output_file="/tmp/outputICCID.txt"
echo "AT+ICCID" > "$input_file"
atinout "$input_file" /dev/smd11 "$output_file"
atinout "$input_file" "/dev/$AT_PORT" "$output_file"
iccid=$(cat "$output_file" | grep "+ICCID:" | cut -d' ' -f2)
@@ -92,7 +128,7 @@ set_apn() {
local output_file="/tmp/outputAPN.txt"
echo "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0" > "$input_file"
atinout "$input_file" /dev/smd11 "$output_file"
atinout "$input_file" "/dev/$AT_PORT" "$output_file"
local result=$(cat "$output_file")
rm -f "$input_file" "$output_file"
@@ -128,15 +164,15 @@ fi
EOF
# Make the script executable
chmod +x /etc/quecmanager/apnProfiles.sh
chmod +x /etc/quecmanager/apn_profile/apnProfiles.sh
# Add to rc.local if not already present
if ! grep -q "/etc/quecmanager/apnProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/apnProfiles.sh' /etc/rc.local
if ! grep -q "/etc/quecmanager/apn_profile/apnProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/apn_profile/apnProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/apnProfiles.sh
/etc/quecmanager/apn_profile/apnProfiles.sh
# Check the result
if [ -f /tmp/apn_result.txt ]; then

View File

@@ -1,66 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+CGDCONT?' 'AT+QNWPREFCFG="mode_pref"' 'AT+QNWPREFCFG="nr5g_disable_mode"' 'AT+QUIMSLOT?'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -1,45 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/apn_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"status": "error", "message": "No APN profiles found", "profiles": {}}'
exit 0
fi
# Function to read config values
get_config_value() {
local key=$1
local value=$(grep "^${key}=" "$CONFIG_FILE" | cut -d'=' -f2)
echo "$value"
}
# Read all profile values
iccidProfile1=$(get_config_value "iccidProfile1")
apnProfile1=$(get_config_value "apnProfile1")
pdpType1=$(get_config_value "pdpType1")
iccidProfile2=$(get_config_value "iccidProfile2")
apnProfile2=$(get_config_value "apnProfile2")
pdpType2=$(get_config_value "pdpType2")
# Construct JSON response
cat << EOF
{
"status": "success",
"profiles": {
"profile1": {
"iccid": "${iccidProfile1:-}",
"apn": "${apnProfile1:-}",
"pdpType": "${pdpType1:-}"
},
"profile2": {
"iccid": "${iccidProfile2:-}",
"apn": "${apnProfile2:-}",
"pdpType": "${pdpType2:-}"
}
}
}
EOF

View File

@@ -0,0 +1,66 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error flag
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Remove the entire quecmanager directory
if [ -d "/etc/quecmanager/imei_profile/" ]; then
rm -rf /etc/quecmanager/imei_profile/
if [ $? -ne 0 ]; then
append_error "Failed to remove quecmanager directory"
fi
else
append_error "quecmanager directory not found"
fi
# Remove the line from rc.local
if [ -f "/etc/rc.local" ]; then
# Create a temporary file
temp_file=$(mktemp)
# Remove the imeiProfiles.sh line and copy to temp file
sed '/\/etc\/quecmanager\/imeiProfiles.sh/d' /etc/rc.local > "$temp_file"
# Check if sed command was successful
if [ $? -eq 0 ]; then
# Replace original file with modified version
mv "$temp_file" /etc/rc.local
if [ $? -ne 0 ]; then
append_error "Failed to update rc.local"
fi
else
append_error "Failed to modify rc.local"
rm -f "$temp_file"
fi
else
append_error "rc.local file not found"
fi
# Remove temporary files that might have been created
rm -f /tmp/imei_result.txt
rm -f /tmp/debug.log
rm -f /tmp/inputICCID.txt
rm -f /tmp/outputICCID.txt
rm -f /tmp/inputIMEI.txt
rm -f /tmp/outputIMEI.txt
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"IMEI profiles and configuration successfully removed\"}"
fi

View File

@@ -0,0 +1,39 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/imei_profile/imei_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo "{}"
exit 0
fi
# Read the configuration file
iccidProfile1=$(grep "^iccidProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
imeiProfile1=$(grep "^imeiProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
iccidProfile2=$(grep "^iccidProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
imeiProfile2=$(grep "^imeiProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
# Build the JSON response
echo "{"
# Add Profile 1 if it exists
if [ -n "$iccidProfile1" ]; then
echo " \"profile1\": {"
echo " \"iccid\": \"$iccidProfile1\","
echo " \"imei\": \"$imeiProfile1\""
echo " }"
# Add comma if Profile 2 exists
[ -n "$iccidProfile2" ] && echo " ,"
fi
# Add Profile 2 if it exists
if [ -n "$iccidProfile2" ]; then
echo " \"profile2\": {"
echo " \"iccid\": \"$iccidProfile2\","
echo " \"imei\": \"$imeiProfile2\""
echo " }"
fi
echo "}"

View File

@@ -0,0 +1,209 @@
#!/bin/sh
# Parse POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | grep -o 'iccidProfile1=[^&]*' | cut -d= -f2)
imeiProfile1=$(echo "$QUERY_STRING" | grep -o 'imeiProfile1=[^&]*' | cut -d= -f2)
iccidProfile2=$(echo "$QUERY_STRING" | grep -o 'iccidProfile2=[^&]*' | cut -d= -f2)
imeiProfile2=$(echo "$QUERY_STRING" | grep -o 'imeiProfile2=[^&]*' | cut -d= -f2)
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
imeiProfile1=$(urldecode "$imeiProfile1")
iccidProfile2=$(urldecode "$iccidProfile2")
imeiProfile2=$(urldecode "$imeiProfile2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$imeiProfile1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Check the directory if it exists, if not create it
if [ ! -d /etc/quecmanager/imei_profile ]; then
mkdir -p /etc/quecmanager/imei_profile
fi
# Create a configuration file to store IMEI profiles
cat >/etc/quecmanager/imei_profile/imei_config.txt <<EOF
iccidProfile1=$iccidProfile1
imeiProfile1=$imeiProfile1
EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >>/etc/quecmanager/imei_profile/imei_config.txt <<EOF
iccidProfile2=$iccidProfile2
imeiProfile2=$imeiProfile2
EOF
fi
# Create the imeiProfiles.sh script
cat >/etc/quecmanager/imei_profile/imeiProfiles.sh <<'EOF'
#!/bin/sh
# Function to read config values
get_config_value() {
local key=$1
grep "^${key}=" /etc/quecmanager/imei_profile/imei_config.txt | cut -d'=' -f2
}
# Read configuration
iccidProfile1=$(get_config_value "iccidProfile1")
imeiProfile1=$(get_config_value "imeiProfile1")
iccidProfile2=$(get_config_value "iccidProfile2")
imeiProfile2=$(get_config_value "imeiProfile2")
# Debug logging
DEBUG_LOG="/tmp/debug.log"
echo "Starting IMEI profile script at $(date)" > "$DEBUG_LOG"
CONFIG_FILE="/etc/quecManager.conf"
# Check config file
if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file not found: $CONFIG_FILE" >> "$DEBUG_LOG"
echo '{"error": "Config file not found"}'
exit 1
fi
# Get AT_PORT with debug logging
AT_PORT=$(head -n 1 "$CONFIG_FILE" | cut -d'=' -f2 | tr -d ' \n\r' | sed 's|^dev/||')
echo "Raw config line: $(head -n 1 "$CONFIG_FILE")" >> "$DEBUG_LOG"
echo "Extracted AT_PORT: '$AT_PORT'" >> "$DEBUG_LOG"
if [ -z "$AT_PORT" ]; then
echo "AT_PORT is empty" >> "$DEBUG_LOG"
echo '{"error": "Failed to read AT_PORT from config"}'
exit 1
fi
# Check if AT_PORT exists
if [ ! -c "/dev/$AT_PORT" ]; then
echo "AT_PORT device not found: /dev/$AT_PORT" >> "$DEBUG_LOG"
echo '{"error": "AT_PORT device not found"}'
exit 1
fi
# Function to get current ICCID
get_current_iccid() {
local input_file="/tmp/inputICCID.txt"
local output_file="/tmp/outputICCID.txt"
echo "AT+ICCID" > "$input_file"
atinout "$input_file" "/dev/$AT_PORT" "$output_file"
iccid=$(cat "$output_file" | grep "+ICCID:" | cut -d' ' -f2)
rm -f "$input_file" "$output_file"
echo "$iccid"
}
# Function to get current IMEI
get_current_imei() {
local input_file="/tmp/inputCGSN.txt"
local output_file="/tmp/outputCGSN.txt"
echo "AT+CGSN" > "$input_file"
atinout "$input_file" "/dev/$AT_PORT" "$output_file"
# Extract IMEI from the response, removing any whitespace or newlines
imei=$(cat "$output_file" | grep -v "AT+CGSN" | grep -v "OK" | tr -d '\r\n[:space:]')
rm -f "$input_file" "$output_file"
echo "$imei"
}
# Function to set IMEI
set_imei() {
local imei="$1"
local input_file="/tmp/inputIMEI.txt"
local output_file="/tmp/outputIMEI.txt"
echo "AT+EGMR=1,7,\"$imei\";+QPOWD=1" > "$input_file"
atinout "$input_file" "/dev/$AT_PORT" "$output_file"
local result=$(cat "$output_file")
rm -f "$input_file" "$output_file"
if echo "$result" | grep -q "OK"; then
return 0
else
return 1
fi
}
# Get current ICCID and IMEI
current_iccid=$(get_current_iccid)
current_imei=$(get_current_imei)
success=false
echo "Current ICCID: $current_iccid" >> "$DEBUG_LOG"
echo "Current IMEI: $current_imei" >> "$DEBUG_LOG"
echo "Profile 1 - ICCID: $iccidProfile1, IMEI: $imeiProfile1" >> "$DEBUG_LOG"
echo "Profile 2 - ICCID: $iccidProfile2, IMEI: $imeiProfile2" >> "$DEBUG_LOG"
# Check ICCID against profile 1 (required)
if [ "$current_iccid" = "$iccidProfile1" ]; then
if [ "$current_imei" != "$imeiProfile1" ]; then
echo "ICCID matches profile 1, but IMEI needs updating" >> "$DEBUG_LOG"
if set_imei "$imeiProfile1"; then
success=true
fi
else
echo "ICCID and IMEI already match profile 1, no action needed" >> "$DEBUG_LOG"
success=true
fi
# Check ICCID against profile 2 (optional)
elif [ -n "$iccidProfile2" ] && [ "$current_iccid" = "$iccidProfile2" ]; then
if [ "$current_imei" != "$imeiProfile2" ]; then
echo "ICCID matches profile 2, but IMEI needs updating" >> "$DEBUG_LOG"
if set_imei "$imeiProfile2"; then
success=true
fi
else
echo "ICCID and IMEI already match profile 2, no action needed" >> "$DEBUG_LOG"
success=true
fi
fi
if [ "$success" = "true" ]; then
echo "IMEI check/update completed successfully" > /tmp/imei_result.txt
else
echo "Failed to check/update IMEI" > /tmp/imei_result.txt
fi
EOF
# Make the script executable
chmod +x /etc/quecmanager/imei_profile/imeiProfiles.sh
# Add to rc.local if not already present
if ! grep -q "/etc/quecmanager/imei_profile/imeiProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/imei_profile/imeiProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/imei_profile/imeiProfiles.sh
# Check the result
if [ -f /tmp/imei_result.txt ]; then
result=$(cat /tmp/imei_result.txt)
rm -f /tmp/imei_result.txt
if [ "$result" = "IMEI set successfully" ]; then
echo '{"status": "success", "message": "IMEI profiles saved and applied successfully"}'
else
echo '{"status": "error", "message": "IMEI profiles saved but failed to apply"}'
fi
else
echo '{"status": "error", "message": "Something went wrong while processing IMEI profiles"}'
fi

View File

@@ -1,14 +0,0 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Ping 8.8.8.8 and capture the result
if ping -c 1 8.8.8.8 > /dev/null 2>&1; then
# Ping was successful
echo '{"connection": "ACTIVE"}'
else
# Ping failed
echo '{"connection": "INACTIVE"}'
fi

View File

@@ -0,0 +1,61 @@
#!/bin/sh
# Configuration and log directories
CONFIG_DIR="/etc/quecmanager/quecwatch"
QUECWATCH_SCRIPT="${CONFIG_DIR}/quecwatch.sh"
RCLOCAL="/etc/rc.local"
LOG_DIR="/tmp/log/quecwatch"
DEBUG_LOG_FILE="${LOG_DIR}/debug.log"
# Log directory for cleaning process
CLEANUP_LOG_FILE="${LOG_DIR}/cleanup.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
# Function to log cleanup events
log_cleanup() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${CLEANUP_LOG_FILE}"
}
# Default response headers
echo "Content-type: application/json"
echo ""
# Cleanup function
cleanup_quecwatch() {
# Start logging cleanup process
log_cleanup "Starting QuecWatch cleanup process"
# Stop any running QuecWatch processes
log_cleanup "Stopping QuecWatch processes"
pkill -f "${QUECWATCH_SCRIPT}" >> "${CLEANUP_LOG_FILE}" 2>&1
# Remove QuecWatch script from rc.local
if [ -f "${RCLOCAL}" ]; then
log_cleanup "Removing QuecWatch entries from rc.local"
sed -i '\|/etc/quecmanager/quecwatch/quecwatch.sh|d' "${RCLOCAL}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
# Remove configuration directory
if [ -d "${CONFIG_DIR}" ]; then
log_cleanup "Removing configuration directory: ${CONFIG_DIR}"
rm -rf "${CONFIG_DIR}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
# Remove log directory
if [ -d "${LOG_DIR}" ]; then
log_cleanup "Removing log directory: ${LOG_DIR}"
rm -rf "${LOG_DIR}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
log_cleanup "QuecWatch cleanup completed successfully"
# Optional: Output JSON response
echo '{"status": "success", "message": "QuecWatch disabled and removed"}'
}
# Execute cleanup
cleanup_quecwatch
exit 0

View File

@@ -0,0 +1,356 @@
#!/bin/sh
# Read POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Configuration directory
CONFIG_DIR="/etc/quecmanager/quecwatch"
QUECWATCH_CONFIG="${CONFIG_DIR}/quecwatch.conf"
QUECWATCH_SCRIPT="${CONFIG_DIR}/quecwatch.sh"
RCLOCAL="/etc/rc.local"
LOG_DIR="/tmp/log/quecwatch"
DEBUG_LOG_FILE="${LOG_DIR}/debug.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
# Extract values from POST data
action=$(echo "$QUERY_STRING" | grep -o 'action=[^&]*' | cut -d= -f2)
ping_target=$(echo "$QUERY_STRING" | grep -o 'ping_target=[^&]*' | cut -d= -f2)
ping_interval=$(echo "$QUERY_STRING" | grep -o 'ping_interval=[^&]*' | cut -d= -f2)
ping_failures=$(echo "$QUERY_STRING" | grep -o 'ping_failures=[^&]*' | cut -d= -f2)
max_retries=$(echo "$QUERY_STRING" | grep -o 'max_retries=[^&]*' | cut -d= -f2)
connection_refresh=$(echo "$QUERY_STRING" | grep -o 'connection_refresh=[^&]*' | cut -d= -f2)
auto_sim_failover=$(echo "$QUERY_STRING" | grep -o 'auto_sim_failover=[^&]*' | cut -d= -f2)
sim_failover_schedule=$(echo "$QUERY_STRING" | grep -o 'sim_failover_schedule=[^&]*' | cut -d= -f2)
mobile_data_reconnect=$(echo "$QUERY_STRING" | grep -o 'mobile_data_reconnect=[^&]*' | cut -d= -f2)
# URL decode the values
action=$(urldecode "$action")
ping_target=$(urldecode "$ping_target")
ping_interval=$(urldecode "$ping_interval")
ping_failures=$(urldecode "$ping_failures")
max_retries=$(urldecode "$max_retries")
connection_refresh=$(urldecode "$connection_refresh")
auto_sim_failover=$(urldecode "$auto_sim_failover")
sim_failover_schedule=$(urldecode "$sim_failover_schedule")
mobile_data_reconnect=$(urldecode "$mobile_data_reconnect")
# Default response headers
echo "Content-type: application/json"
echo ""
# Validate inputs
if [ -z "$ping_target" ]; then
echo '{"status": "error", "message": "Ping target is required"}'
exit 1
fi
# Initialize configuration function
initialize_config() {
# Create config directory if not exists
mkdir -p "${CONFIG_DIR}"
# Write configuration with defaults and user-provided values
cat >"${QUECWATCH_CONFIG}" <<EOL
# QuecWatch Configuration File
# Ping Target (IP or domain to ping)
PING_TARGET=${ping_target}
# Interval between ping checks (in seconds)
PING_INTERVAL=${ping_interval:-30}
# Number of consecutive ping failures before taking action
PING_FAILURES=${ping_failures:-3}
# Maximum number of retry attempts
MAX_RETRIES=${max_retries:-5}
# Current retry count (should start at 0)
CURRENT_RETRIES=0
# Enable/Disable Connection Refresh
CONNECTION_REFRESH=${connection_refresh:-false}
# Number of connection refresh attempts
REFRESH_COUNT=${connection_refresh:+3}
# Enable/Disable Auto SIM Failover
AUTO_SIM_FAILOVER=${auto_sim_failover:-false}
# Schedule for checking initial SIM (in minutes)
# 0 means no scheduled check
SIM_FAILOVER_SCHEDULE=${sim_failover_schedule:-0}
# Enable/Disable Mobile Data Reconnect
MOBILE_DATA_RECONNECT=${mobile_data_reconnect:-false}
# Indicate that QuecWatch is enabled
ENABLED=true
EOL
chmod 644 "${QUECWATCH_CONFIG}"
}
# Generate monitoring script function
generate_monitoring_script() {
cat >"${QUECWATCH_SCRIPT}" <<'EOL'
#!/bin/sh
# Load configuration
. /etc/quecmanager/quecwatch/quecwatch.conf
# Log directory
LOG_DIR="/tmp/log/quecwatch"
mkdir -p "${LOG_DIR}"
# Function to log events
log_event() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${LOG_DIR}/quecwatch.log"
}
# Function to update retry count in config
update_retry_count() {
local new_retry_count=$1
sed -i "s/CURRENT_RETRIES=[0-9]*/CURRENT_RETRIES=${new_retry_count}/" /etc/quecmanager/quecwatch/quecwatch.conf
# Reload config to ensure latest values
. /etc/quecmanager/quecwatch/quecwatch.conf
}
# Function to switch SIM card
switch_sim_card() {
log_event "Attempting to switch SIM card"
# Create log directory if it doesn't exist
mkdir -p /tmp/log/quecwatch
# Get current SIM slot using AT command
echo AT+QUIMSLOT? | atinout - /dev/smd7 /tmp/log/quecwatch/current_sim.txt
# Extract numerical value from the output
current_sim_slot=$(grep "+QUIMSLOT:" /tmp/log/quecwatch/current_sim.txt | awk '{print $2}')
# Toggle between SIM slots (assuming 2 SIM slots)
if [ "${current_sim_slot}" = "1" ]; then
new_sim_slot=2
else
new_sim_slot=1
fi
# Explicitly set the new SIM slot
log_event "Switching from SIM slot ${current_sim_slot} to SIM slot ${new_sim_slot}"
# Add your SIM switching command here
# Example (adjust based on your modem's AT commands):
echo "AT+QUIMSLOT=${new_sim_slot}" | atinout - /dev/smd7 -
# Update current_sim_slot with the new value
current_sim_slot=${new_sim_slot}
}
# Function to toggle mobile data
toggle_mobile_data() {
log_event "Toggling mobile data"
# Use CFUN to restart mobile functionality
echo AT+CFUN=0 | atinout - /dev/smd7 -
#sleep 5
echo AT+CFUN=1 | atinout - /dev/smd7 -
}
# Function to perform connection recovery
perform_connection_recovery() {
local recovery_attempted=0
# 1. Try Connection Refresh first if enabled (when retry_trigger is 1)
if [ "${CONNECTION_REFRESH}" = "true" ] && [ "${retry_trigger}" -eq 1 ] && [ "${REFRESH_COUNT}" -gt 0 ]; then
log_event "Attempting connection refresh"
echo AT+COPS=2 | atinout - /dev/smd7 -
sleep 2
echo AT+COPS=0 | atinout - /dev/smd7 -
# Verify connection after refresh
if ping -c 3 ${PING_TARGET} > /dev/null 2>&1; then
log_event "Connection refresh successful"
return 0
fi
# Decrement refresh count
REFRESH_COUNT=$((REFRESH_COUNT - 1))
sed -i "s/REFRESH_COUNT=.*/REFRESH_COUNT=${REFRESH_COUNT}/" /etc/quecmanager/quecwatch/quecwatch.conf
recovery_attempted=1
fi
# 2. Try Auto SIM Failover when retry_trigger is 2 (or 1 if Connection Refresh is disabled)
local sim_failover_trigger=$((CONNECTION_REFRESH == "true" ? 2 : 1))
if [ "${AUTO_SIM_FAILOVER}" = "true" ] && [ "${retry_trigger}" -eq ${sim_failover_trigger} ]; then
log_event "Attempting SIM failover"
# Get current SIM slot
echo AT+QUIMSLOT? | atinout - /dev/smd7 /tmp/log/quecwatch/current_sim.txt
initial_sim_slot=$(grep "+QUIMSLOT:" /tmp/log/quecwatch/current_sim.txt | awk '{print $2}')
# Switch SIM card
switch_sim_card
# Verify connection after SIM switch
if ping -c 3 ${PING_TARGET} > /dev/null 2>&1; then
log_event "SIM failover successful"
return 0
fi
recovery_attempted=1
fi
# 3. Try Mobile Data Reconnect if enabled
if [ "${MOBILE_DATA_RECONNECT}" = "true" ]; then
log_event "Attempting mobile data reconnect"
toggle_mobile_data
# Verify connection after mobile data toggle
if ping -c 3 ${PING_TARGET} > /dev/null 2>&1; then
log_event "Mobile data reconnect successful"
return 0
fi
recovery_attempted=1
fi
# 4. If no recovery methods worked or none were enabled, return failure
if [ ${recovery_attempted} -eq 0 ]; then
log_event "No recovery methods enabled"
return 1
fi
return 1
}
while true; do
# Ping the target
if ! ping -c ${PING_FAILURES} ${PING_TARGET} > /dev/null 2>&1; then
failure_count=$((failure_count + 1))
log_event "Ping failed. Failure count: ${failure_count}"
# Check if failure threshold is reached
if [ ${failure_count} -ge ${PING_FAILURES} ]; then
# Reset failure count
failure_count=0
retry_trigger=$((retry_trigger + 1))
# Update retry count in config
update_retry_count ${retry_trigger}
log_event "Failure threshold reached. Retry trigger: ${retry_trigger}"
# Check if retry threshold is reached
if [ ${retry_trigger} -ge ${MAX_RETRIES} ]; then
log_event "Max retries exhausted. Removing QuecWatch."
# Remove the script from rc.local
sed -i '\|/etc/quecmanager/quecwatch/quecwatch.sh|d' /etc/rc.local
# Perform final system reboot
reboot
exit 0
fi
# Attempt connection recovery
if perform_connection_recovery; then
# Recovery successful
log_event "Connection recovery successful"
retry_trigger=0
failure_count=0
update_retry_count 0
else
# Recovery failed, choose recovery method based on configurations
if [ "${MOBILE_DATA_RECONNECT}" = "true" ]; then
log_event "Recovery failed. Attempting mobile data restart."
toggle_mobile_data
else
log_event "Recovery failed. Rebooting system."
reboot
fi
fi
fi
else
# Reset failure count and retry trigger if connection is good
failure_count=0
retry_trigger=0
update_retry_count 0
# Add success log message
log_event "Modem is connected to the internet"
# Check if SIM Failover Scheduler is enabled and interval has passed
if [ "${AUTO_SIM_FAILOVER}" = "true" ] && [ "${SIM_FAILOVER_SCHEDULE}" -gt 0 ]; then
sim_failover_interval=$((sim_failover_interval + 1))
# Check if it's time to switch back to initial SIM
if [ $((sim_failover_interval * ${PING_INTERVAL})) -ge $((${SIM_FAILOVER_SCHEDULE} * 60)) ]; then
log_event "Checking initial SIM card"
# Only switch back if max retries were NOT exhausted
if [ ${retry_trigger} -lt ${MAX_RETRIES} ]; then
# Switch back to initial SIM
echo AT+QUIMSLOT=${initial_sim_slot} | atinout - /dev/smd7 -
# Check connection on initial SIM
if ping -c 3 ${PING_TARGET} > /dev/null 2>&1; then
log_event "Initial SIM restored successfully"
current_sim_slot=${initial_sim_slot}
# Reset retry trigger when switching back
retry_trigger=0
failure_count=0
update_retry_count 0
else
log_event "Initial SIM still not working. Remaining on failover SIM."
fi
# Reset interval counter
sim_failover_interval=0
fi
fi
fi
fi
# Wait for specified interval before next check
sleep ${PING_INTERVAL}
done
EOL
chmod +x "${QUECWATCH_SCRIPT}"
# Run the script
"${QUECWATCH_SCRIPT}" &
}
# Enable QuecWatch
enable_quecwatch() {
# Initialize configuration
initialize_config
# Generate monitoring script
generate_monitoring_script
# Add to rc.local if not already present
if ! grep -q "${QUECWATCH_SCRIPT}" "${RCLOCAL}"; then
[ -f "${RCLOCAL}" ] || touch "${RCLOCAL}"
chmod +x "${RCLOCAL}"
sed -i '$i'"${QUECWATCH_SCRIPT} &" "${RCLOCAL}"
fi
# Output success JSON
echo '{"status": "success", "message": "QuecWatch enabled", "config": "'${QUECWATCH_CONFIG}'"}'
}
# Log debug information
{
echo "Timestamp: $(date)"
echo "Script Path: $0"
echo "Ping Target: $ping_target"
echo "Ping Interval: $ping_interval"
echo "Ping Failures: $ping_failures"
echo "Max Retries: $max_retries"
echo "Connection Refresh: $connection_refresh"
echo "Auto SIM Failover: $auto_sim_failover"
echo "SIM Failover Schedule: $sim_failover_schedule"
echo "Mobile Data Reconnect: $mobile_data_reconnect"
} >>"$DEBUG_LOG_FILE" 2>&1
# Enable QuecWatch
enable_quecwatch
exit 0

View File

@@ -0,0 +1,79 @@
#!/bin/sh
# Set headers for JSON response
echo "Content-type: application/json"
echo ""
# Configuration file path
CONFIG_FILE="/etc/quecmanager/quecwatch/quecwatch.conf"
# Check if configuration file exists
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"status": "inactive", "message": "QuecWatch is not configured"}'
exit 0
fi
# Function to safely get config value
get_config_value() {
grep "^$1=" "$CONFIG_FILE" | cut -d'=' -f2
}
# Check if QuecWatch is enabled
enabled=$(get_config_value "ENABLED")
if [ "$enabled" != "true" ]; then
echo '{"status": "inactive", "message": "QuecWatch is disabled"}'
exit 0
fi
# Fetch configuration values
ping_target=$(get_config_value "PING_TARGET")
ping_interval=$(get_config_value "PING_INTERVAL")
ping_failures=$(get_config_value "PING_FAILURES")
max_retries=$(get_config_value "MAX_RETRIES")
current_retries=$(get_config_value "CURRENT_RETRIES")
connection_refresh=$(get_config_value "CONNECTION_REFRESH")
refresh_count=$(get_config_value "REFRESH_COUNT")
# New configuration options
mobile_data_reconnect=$(get_config_value "MOBILE_DATA_RECONNECT")
auto_sim_failover=$(get_config_value "AUTO_SIM_FAILOVER")
sim_failover_schedule=$(get_config_value "SIM_FAILOVER_SCHEDULE")
# Default values if not set
mobile_data_reconnect=${mobile_data_reconnect:-false}
auto_sim_failover=${auto_sim_failover:-false}
sim_failover_schedule=${sim_failover_schedule:-30}
# Check monitoring script existence
QUECWATCH_SCRIPT="/etc/quecmanager/quecwatch/quecwatch.sh"
if [ ! -f "$QUECWATCH_SCRIPT" ]; then
echo '{"status": "error", "message": "Monitoring script is missing"}'
exit 0
fi
# Check log file for recent activity
LOG_FILE="/tmp/log/quecwatch/quecwatch.log"
last_log=""
if [ -f "$LOG_FILE" ]; then
last_log=$(tail -n 1 "$LOG_FILE")
fi
# Prepare JSON response
cat <<EOF
{
"status": "active",
"config": {
"pingTarget": "${ping_target}",
"pingInterval": ${ping_interval},
"pingFailures": ${ping_failures},
"maxRetries": ${max_retries},
"currentRetries": ${current_retries},
"connectionRefresh": ${connection_refresh},
"refreshCount": ${refresh_count:-0},
"mobileDataReconnect": ${mobile_data_reconnect},
"autoSimFailover": ${auto_sim_failover},
"simFailoverSchedule": ${sim_failover_schedule}
},
"lastActivity": "${last_log}"
}
EOF

View File

@@ -1,45 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/apn_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"status": "error", "message": "No APN profiles found", "profiles": {}}'
exit 0
fi
# Function to read config values
get_config_value() {
local key=$1
local value=$(grep "^${key}=" "$CONFIG_FILE" | cut -d'=' -f2)
echo "$value"
}
# Read all profile values
iccidProfile1=$(get_config_value "iccidProfile1")
apnProfile1=$(get_config_value "apnProfile1")
pdpType1=$(get_config_value "pdpType1")
iccidProfile2=$(get_config_value "iccidProfile2")
apnProfile2=$(get_config_value "apnProfile2")
pdpType2=$(get_config_value "pdpType2")
# Construct JSON response
cat << EOF
{
"status": "success",
"profiles": {
"profile1": {
"iccid": "${iccidProfile1:-}",
"apn": "${apnProfile1:-}",
"pdpType": "${pdpType1:-}"
},
"profile2": {
"iccid": "${iccidProfile2:-}",
"apn": "${apnProfile2:-}",
"pdpType": "${pdpType2:-}"
}
}
}
EOF

View File

@@ -0,0 +1,141 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Function to output error in JSON format
output_error() {
echo "{\"error\": \"$1\"}"
exit 1
}
# Define command sets
define_command_sets() {
COMMAND_SET_1='AT+QUIMSLOT? AT+CNUM AT+COPS? AT+CIMI AT+ICCID AT+CGSN AT+CPIN? AT+CGDCONT? AT+CREG? AT+CFUN? AT+QENG="servingcell" AT+QTEMP AT+CGCONTRDP AT+QCAINFO AT+QRSRP AT+QMAP="WWAN" AT+C5GREG=2;+C5GREG? AT+CGREG=2;+CGREG? AT+QRSRQ AT+QSINR'
COMMAND_SET_2='AT+CGDCONT? AT+CGCONTRDP AT+QNWPREFCFG="mode_pref" AT+QNWPREFCFG="nr5g_disable_mode" AT+QUIMSLOT?'
COMMAND_SET_3='AT+CGMI AT+CGMM AT+QGMR AT+CNUM AT+CIMI AT+ICCID AT+CGSN AT+QMAP="LANIP" AT+QMAP="WWAN" AT+QGETCAPABILITY'
COMMAND_SET_4='AT+QMAP="MPDN_RULE" AT+QMAP="DHCPV4DNS" AT+QCFG="usbnet"'
COMMAND_SET_5='AT+QRSRP AT+QRSRQ AT+QSINR AT+QCAINFO AT+QSPN'
COMMAND_SET_6='AT+CEREG=2;+CEREG? AT+C5GREG=2;+C5GREG? AT+CPIN? AT+CGDCONT? AT+CGCONTRDP AT+QMAP="WWAN" AT+QRSRP AT+QTEMP AT+QNETRC?'
}
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200 || output_error "Unable to acquire lock"
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
# Debug logging
DEBUG_LOG="/tmp/debug.log"
echo "Starting script at $(date)" > "$DEBUG_LOG"
CONFIG_FILE="/etc/quecManager.conf"
# Check config file
if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file not found: $CONFIG_FILE" >> "$DEBUG_LOG"
output_error "Config file not found"
fi
# Get AT_PORT with debug logging
AT_PORT=$(head -n 1 "$CONFIG_FILE" | cut -d'=' -f2 | tr -d ' \n\r' | sed 's|^dev/||')
echo "Raw config line: $(head -n 1 "$CONFIG_FILE")" >> "$DEBUG_LOG"
echo "Extracted AT_PORT: '$AT_PORT'" >> "$DEBUG_LOG"
if [ -z "$AT_PORT" ]; then
echo "AT_PORT is empty" >> "$DEBUG_LOG"
output_error "Failed to read AT_PORT from config"
fi
# Check if AT_PORT exists
if [ ! -c "/dev/$AT_PORT" ]; then
echo "AT_PORT device not found: /dev/$AT_PORT" >> "$DEBUG_LOG"
echo "Available smd devices:" >> "$DEBUG_LOG"
ls -l /dev/smd* >> "$DEBUG_LOG" 2>&1
output_error "AT_PORT device not found"
fi
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Function to process AT commands
process_commands() {
local commands="$1"
local json_response="["
for cmd in $commands; do
echo "Processing command: $cmd" >> "$DEBUG_LOG"
# Write the command to the input file
echo "$cmd" > "$INPUT_FILE"
# Run the command using atinout with full path to device
if ! atinout "$INPUT_FILE" "/dev/$AT_PORT" "$OUTPUT_FILE" 2>> "$DEBUG_LOG"; then
echo "Command failed: $cmd" >> "$DEBUG_LOG"
OUTPUT="Error executing command"
elif [ ! -f "$OUTPUT_FILE" ]; then
echo "Output file not created for command: $cmd" >> "$DEBUG_LOG"
OUTPUT="No output file"
else
OUTPUT=$(cat "$OUTPUT_FILE" 2>> "$DEBUG_LOG" || echo "Error reading output")
echo "Command output: $OUTPUT" >> "$DEBUG_LOG"
fi
# Escape special characters for JSON
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response
json_response="${json_response}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${json_response: -1}" = "," ]; then
json_response="${json_response%,}]"
else
json_response="${json_response}]"
fi
echo "$json_response"
}
# Main execution
define_command_sets
# Get command set from query string
COMMAND_SET=$(echo "$QUERY_STRING" | grep -o 'set=[1-6]' | cut -d'=' -f2)
# Select the appropriate command set
case "$COMMAND_SET" in
1) COMMANDS="$COMMAND_SET_1";;
2) COMMANDS="$COMMAND_SET_2";;
3) COMMANDS="$COMMAND_SET_3";;
4) COMMANDS="$COMMAND_SET_4";;
5) COMMANDS="$COMMAND_SET_5";;
6) COMMANDS="$COMMAND_SET_6";;
*) COMMANDS="$COMMAND_SET_1";; # Default to set 1 if no valid set specified
esac
# Process the selected commands and output the response
JSON_RESPONSE=$(process_commands "$COMMANDS")
echo "$JSON_RESPONSE" >> "$DEBUG_LOG"
echo "$JSON_RESPONSE"
# Clean up temporary files
rm -f "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200
echo "Script completed at $(date)" >> "$DEBUG_LOG"

View File

@@ -1,49 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Create a temporary file to store the processed data
temp_file=$(mktemp)
# Process ARP entries and store in temporary file
arp -a | while IFS= read -r line; do
if [ -n "$line" ]; then
# Extract hostname (or IP if hostname is "?"), IP, and MAC
hostname=$(echo "$line" | awk '{print $1}')
ip=$(echo "$line" | awk -F '[()]' '{print $2}')
mac=$(echo "$line" | awk '{print $4}')
# Skip entries without valid MAC addresses
if [ "$mac" = "<incomplete>" ]; then
continue
fi
# If hostname is "?", use the IP address instead
if [ "$hostname" = "?" ]; then
hostname="$ip"
fi
# Store each entry in the temp file
echo "$hostname:$ip:$mac" >> "$temp_file"
fi
done
# Initialize JSON array
echo -n "["
# Process the temporary file to create JSON
first=true
while IFS=: read -r hostname ip mac; do
if [ "$first" = true ]; then
first=false
else
echo -n ","
fi
echo -n "{\"hostname\":\"$hostname\",\"ip\":\"$ip\",\"mac\":\"$mac\"}"
done < "$temp_file"
# Close the JSON array
echo "]"
# Clean up
rm -f "$temp_file"

View File

@@ -4,8 +4,8 @@
echo "Content-Type: application/json"
echo ""
# Ping 8.8.8.8 and capture the result
if ping -c 1 8.8.8.8 > /dev/null 2>&1; then
# Ping 8.8.8.8 with 5 packets and capture the result
if ping -c 5 8.8.8.8 > /dev/null 2>&1; then
# Ping was successful
echo '{"connection": "ACTIVE"}'
else

View File

@@ -1,66 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in "AT+QUIMSLOT?" "AT+CNUM" "AT+COPS?" "AT+CIMI" "AT+ICCID" "AT+CGSN" "AT+CPIN?" "AT+CGDCONT?" "AT+CREG?" "AT+CFUN?" "AT+QENG=\"servingcell\"" "AT+QTEMP" "AT+CGCONTRDP" "AT+QCAINFO" "AT+QRSRP" 'AT+QMAP="WWAN"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

View File

@@ -1,16 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Get RX and TX bytes from ifconfig eth0
data=$(ifconfig eth0 | grep "RX bytes")
# Extract download (RX) and upload (TX) values using awk
download=$(echo $data | awk '{print $2}' | cut -d':' -f2)
upload=$(echo $data | awk '{print $6}' | cut -d':' -f2)
# Return JSON response
echo "{"
echo " \"download\": \"$download\","
echo " \"upload\": \"$upload\""
echo "}"

Some files were not shown because too many files have changed in this diff Show More