From add813336bc592c04f58e7a7a118773f88a9e500 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 20 Sep 2023 05:13:08 +0000 Subject: [PATCH] first commit --- LICENSE | 661 ++++++++++++++++++ Makefile | 14 + README.md | 4 + luasrc/controller/modemconfig.lua | 11 + luasrc/model/cbi/modem/modemconfig.lua | 150 ++++ po/ru/mmconfig.po | 43 ++ root/etc/uci-defaults/61-luci-app-mmconfig | 7 + root/usr/bin/modemconfig | 29 + root/usr/share/modeminfo/scripts/getmode.sh | 11 + root/usr/share/modeminfo/scripts/modemconfig | 125 ++++ .../share/rpcd/acl.d/luci-app-mmconfig.json | 11 + screenshot.png | Bin 0 -> 32963 bytes 12 files changed, 1066 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 luasrc/controller/modemconfig.lua create mode 100644 luasrc/model/cbi/modem/modemconfig.lua create mode 100644 po/ru/mmconfig.po create mode 100644 root/etc/uci-defaults/61-luci-app-mmconfig create mode 100644 root/usr/bin/modemconfig create mode 100644 root/usr/share/modeminfo/scripts/getmode.sh create mode 100644 root/usr/share/modeminfo/scripts/modemconfig create mode 100644 root/usr/share/rpcd/acl.d/luci-app-mmconfig.json create mode 100644 screenshot.png diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ba30bc4 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Configrure modem bands via mmcli utility +LUCI_DEPENDS:=+modemmanager +luci-compat +PKG_LICENSE:=GPLv3 +PKG_VERSION:=0.0.5-4 + +define Package/luci-app-mmconfig/postrm + rm -f /etc/config/modemconfig +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/README.md b/README.md new file mode 100644 index 0000000..470348c --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# luci-app-mmconfig +The OpenWrt Luci app configure modem cellular bands via mmcli utility + +![](https://raw.githubusercontent.com/koshev-msk/modemfeed/master/luci/applications/luci-app-mmconfig/screenshot.png) diff --git a/luasrc/controller/modemconfig.lua b/luasrc/controller/modemconfig.lua new file mode 100644 index 0000000..beb2865 --- /dev/null +++ b/luasrc/controller/modemconfig.lua @@ -0,0 +1,11 @@ +local nixio = require "nixio" + +module("luci.controller.modemconfig", package.seeall) + +local utl = require "luci.util" + +function index() + entry({"admin", "modem"}, firstchild(), translate("Modem"), 45).acl_depends={"unauthenticated"} + entry({"admin", "modem", "modemconfig"}, cbi("modem/modemconfig"), translate("Band config"), 9).acl_depends={"unauthenticated"} +end + diff --git a/luasrc/model/cbi/modem/modemconfig.lua b/luasrc/model/cbi/modem/modemconfig.lua new file mode 100644 index 0000000..592f702 --- /dev/null +++ b/luasrc/model/cbi/modem/modemconfig.lua @@ -0,0 +1,150 @@ +-- Copyright 2021 Konstantine Shevlakov +-- Licensed to the public under the General Public License 3.0. + +require("nixio.fs") +local uci = require "luci.model.uci" + +local m +local s +local mode2g = os.execute("/usr/share/modeminfo/scripts/getmode.sh 2g") +local mode3g = os.execute("/usr/share/modeminfo/scripts/getmode.sh 3g") +local mode4g = os.execute("/usr/share/modeminfo/scripts/getmode.sh 4g") +local slot = uci.cursor():get_first("modemconfig", "modem", "device") + +if slot == nil then + slot = 0 +end + + +local b2g = {} + +local t = io.popen("mmcli -J -m "..slot.." | jsonfilter -e '@[\"modem\"][\"generic\"][\"supported-bands\"][*]' | grep -v utran", "r") + +for bands in t:lines() do + table.insert(b2g, b2) + b2g[#b2g + 1] = bands +end + + +local b3g = {} + +local f = io.popen("mmcli -J -m "..slot.." | jsonfilter -e '@[\"modem\"][\"generic\"][\"supported-bands\"][*]'|awk '/^utran/{print $1}'", "r") + +for bands in f:lines() do + table.insert(b3g, b3) + b3g[#b3g + 1] = bands +end + + +local b4g = {} + +local p = io.popen("mmcli -J -m "..slot.." | jsonfilter -e '@[\"modem\"][\"generic\"][\"supported-bands\"][*]'|awk '/^eutran/{print $1}'", "r") + +for bands in p:lines() do + table.insert(b4g, b4) + b4g[#b4g + 1] = bands +end + + +local mm = {} +local t = io.popen("mmcli -J -L | jsonfilter -e '@[\"modem-list\"][*]'", "r") + + +m = Map("modemconfig", translate("Configure modem bands"), + translate("Configuration 2G/3G/4G modem frequency bands.")) + +s = m:section(TypedSection, "modem", "

 

" .. translate("Choose bands cellular modem")) +s.anonymous = true + +dev = s:option(ListValue, "device", translate("Modem"), translate("Select modem")) +if mm ~= nil then + for dev in t:lines() do + table.insert(mm, m) + mm[#mm + 1] = dev + end + for b,g in ipairs(mm) do + mm[b] = g + if type(g) ~= "table" then + n = io.popen("mmcli -J -m "..g.." | jsonfilter -e '@[\"modem\"].*[\"model\"]'", "r") + local model = n:read("*l") + n:close() + x = io.popen("mmcli -J -m "..g.." | jsonfilter -e '@[\"modem\"].*[\"device\"]'", "r") + local bus = x:read("*l") + x:close() + dev:value(bus,model) + end + end +end + +--s = m:section(TypedSection, "modem", "

 

" .. translate("Choose bands cellular modem")) +--s.anonymous = true + +-- disable if broken + +netmode = s:option(ListValue, "mode", translate("Net Mode"), +translate("Preffered Network mode select.")) +if mode4g == 0 then + netmode:value("4g", "4G only") +end +if mode4g == 0 and mode3g == 0 then + netmode:value("p4g3g", "4G/3G: preffer 4G") + netmode:value("4gp3g", "4G/3G: preffer 3G") +end +if mode2g == 0 and mode3g == 0 and mode4g == 0 then + netmode:value("p4g3g2g", "4G/3G/2G: preffer 4G") + netmode:value("4gp3g2g", "4G/3G/2G: preffer 3G") + netmode:value("4g3gp2g", "4G/3G/2G: preffer 2G") +end +if mode3g == 0 then + netmode:value("3g", "3G only") +end +if mode3g == 0 and mode2g == 0 then + netmode:value("p3g2g", "3G/2G: preffer 3G") + netmode:value("3gp2g", "3G/2G: preffer 2G") +end +if mode2g == 0 then + netmode:value("2g", "2G only") +end +netmode.default = "p4g3g" + + +if mode2g == 0 then + gsm = s:option(DynamicList, "gsm_band", translate("2G")) + if b2g ~= nil then + for b,g in ipairs(b2g) do + b2g[b] = g + gsm:value(g,g) + end + end + gsm.rmempty = true +end + +if mode3g == 0 then + wcdma = s:option(DynamicList, "3g_band", translate("3G")) + if b3g ~= nil then + for b,g in ipairs(b3g) do + b3g[b] = g + wcdma:value(g,g) + end + end + s.rmempty = true +end + +if mode4g == 0 then + lte = s:option(DynamicList, "lte_band", translate("4G"), translate("Maybe must reconnect cellular interface.
If deselect all bands, then used default band modem config.")) + if b4g ~= nil then + for b,g in ipairs(b4g) do + b4g[b] = g + lte:value(g,g) + end + end + s.rmempty = true +end + +function m.on_after_commit(Map) + luci.sys.call("/usr/bin/modemconfig") +end +s.addremove = true +s.anonymous = true +s.rmempty = true +return m diff --git a/po/ru/mmconfig.po b/po/ru/mmconfig.po new file mode 100644 index 0000000..a2d17a1 --- /dev/null +++ b/po/ru/mmconfig.po @@ -0,0 +1,43 @@ +msgid "" +msgstr "" +"Language: ru\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Konstantine Shevlakov \n" + +#: applications/luci-app-mmconfig/luasrc/controller/modemconfig.lua:8 +msgid "Modem" +msgstr "Модем" + +#: applications/luci-app-mmconfig/luasrc/controller/modemconfig.lua:9 +msgid "Band config" +msgstr "Настройка диапазонов" + +#: applications/luci-app-mmconfig/luasrc/model/cbi/modem/modemconfig.lua:12 +msgid "Configure modem bands" +msgstr "Конфигурация диапазонов модема" + +#: applications/luci-app-mmconfig/luasrc/model/cbi/modem/modemconfig.lua:13 +msgid "Configuration 2G/3G/4G modem frequency bands." +msgstr "Конфигурация 2G/3G/4G частот модема." + +#: applications/luci-app-mmconfig/luasrc/model/cbi/modem/modemconfig.lua:13 +msgid "Choose bands cellular modem" +msgstr "Выбор частот сотовой сети" + +#: applications/luci-app-mmconfig/luasrc/model/cbi/modem/modemconfig.lua:19 +msgid "Net Mode" +msgstr "Режим сети" + +#: applications/luci-app-mmconfig/luasrc/model/cbi/modem/modemconfig.lua:19 +msgid "Preffered Network mode select." +msgstr "Выбор предпочтительного режима сети." + +#: applications/luci-app-mmconfig/luasrc/model/cbi/modem/modemconfig.lua:61 +msgid "Select modem" +msgstr "Выбор модема" + +#: applications/luci-app-mmconfig/luasrc/model/cbi/modem/modemconfig.lua:72 +msgid "Maybe must reconnect cellular interface.
If deselect all bands, then used default band modem config." +msgstr "Возможно потребуется перезапустить сотовое соединение.
Если не выбрано ни одного диапазона, используется конфигурация модема по умолчанию." + diff --git a/root/etc/uci-defaults/61-luci-app-mmconfig b/root/etc/uci-defaults/61-luci-app-mmconfig new file mode 100644 index 0000000..4770af9 --- /dev/null +++ b/root/etc/uci-defaults/61-luci-app-mmconfig @@ -0,0 +1,7 @@ +#!/bin/sh -x + +if [ "$PKG_UPGRADE" != "1" ]; then + touch /etc/config/modemconfig + uci set modemconfig.@modem[0]=modem +fi + diff --git a/root/usr/bin/modemconfig b/root/usr/bin/modemconfig new file mode 100644 index 0000000..6055a9f --- /dev/null +++ b/root/usr/bin/modemconfig @@ -0,0 +1,29 @@ +#!/bin/sh + + +run_config(){ + # get cellular wwan iface name + SECTIONS=$(uci show modemconfig | awk -F [\]\[\@=] '/=modem/{print $3}') + # get device path + DEV=$(uci show network | awk -F [=] '/device/{gsub("'\''",""); print $2}') + for n in $SECTIONS; do + SLOT=$(uci -q get modemconfig.@modem[$n].device) + NETMODE=$(uci -q get modemconfig.@modem[$n].mode) + GET_GSM=$(uci -q get modemconfig.@modem[$n].gsm_band) + GET_3G=$(uci -q get modemconfig.@modem[$n].3g_band) + GET_LTE=$(uci -q get modemconfig.@modem[$n].lte_band) + export SLOT NETMODE GET_GSM GET_3G GET_LTE + for d in $DEV; do + if [ $SLOT = $d ]; then + WWIFACE=$(uci -q show network | grep $d | awk -F [=.] '{print $2}') + fi + done + + /usr/share/modeminfo/scripts/modemconfig && \ + sleep 1 && ifdown $WWIFACE && \ + sleep 1 && ifup $WWIFACE & + done +} + +sleep 10 && run_config & + diff --git a/root/usr/share/modeminfo/scripts/getmode.sh b/root/usr/share/modeminfo/scripts/getmode.sh new file mode 100644 index 0000000..77a3086 --- /dev/null +++ b/root/usr/share/modeminfo/scripts/getmode.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +case $1 in + 2g|3g|4g) + SLOT=$(uci -q get modemconfig.@modem[-1].device) + if [ $SLOT ]; then + mmcli -J -m ${SLOT} | jsonfilter -e '@["modem"]["generic"]["supported-modes"][*]' | grep $1 + fi + ;; +esac + diff --git a/root/usr/share/modeminfo/scripts/modemconfig b/root/usr/share/modeminfo/scripts/modemconfig new file mode 100644 index 0000000..2b6f051 --- /dev/null +++ b/root/usr/share/modeminfo/scripts/modemconfig @@ -0,0 +1,125 @@ +#!/bin/sh + +#NETMODE=$(uci -q get modemconfig.@modem[0].mode) +#GET_GSM=$(uci -q get modemconfig.@modem[0].gsm_band) +#GET_3G=$(uci -q get modemconfig.@modem[0].3g_band) +#GET_LTE=$(uci -q get modemconfig.@modem[0].lte_band) +#SLOT=$(/usr/bin/mmcli -L | awk '{print $1}' | awk -F [\/] '{print $NF}' | head -1) + +BAND2G="" +BAND3G="" +BAND4G="" + +# Control empty bands +get_bands(){ + if [ "$GET_BAND" ]; then + continue + else + return + fi + +} + +# Network Mode prefs +set_mode(){ + case $NETMODE in + 2g) + NMODE=2g + PREFMODE=none + ;; + 3g) + NMODE=3g + PREFMODE=none + ;; + 4g) + NMODE=4g + PREFMODE=none + ;; + 3gp2g) + NMODE="2g|3g" + PREFMODE=2g + ;; + p3g2g) + NMODE="2g|3g" + PREFMODE=3g + ;; + p4g3g2g) + NMODE="2g|3g|4g" + PREFMODE="4g" + ;; + 4gp3g2g) + NMODE="2g|3g|4g" + PREFMODE=3g + ;; + 4g3gp2g) + NMODE="2g|3g|4g" + PREFMODE=2g + ;; + p4g3g) + NMODE="4g|3g" + PREFMODE="4g" + ;; + 4gp3g) + NMODE="4g|3g" + PREFMODE="3g" + ;; + esac +} + +# Select 2G bands +set_2g(){ + GET_BAND="$GET_GSM" + get_bands + for g in $GET_BAND; do + BAND2G="$g|$BAND2G" + done +} + +# Select 3G bands +set_3g(){ + GET_BAND="$GET_3G" + get_bands + for g in $GET_BAND; do + BAND3G="$g|$BAND3G" + done +} + +# Select 4G bands +set_4g(){ + GET_BAND="$GET_LTE" + get_bands + for g in $GET_BAND; do + BAND4G="$g|$BAND4G" + done +} +# Reset to defautls bands +reset_to_defaults(){ + DEFBAND="" + SUPPORTED_BANDS="$(echo $(mmcli -J -m $SLOT | jsonfilter -e '@["modem"]["generic"]["supported-bands"][*]'))" + for g in $SUPPORTED_BANDS; do + DEFBAND="$g|$DEFBAND" + done + DEFBAND=$(echo $DEFBAND | sed 's/.$//') +} + +set_2g +set_3g +set_4g + +BAND=$(echo ${BAND2G}${BAND3G}${BAND4G} | sed 's/.$//') + # Select band +if [ "$BAND" ]; then + /usr/bin/mmcli -m $SLOT --set-current-bands="$BAND" +else + reset_to_defaults + /usr/bin/mmcli -m $SLOT --set-current-bands="$DEFBAND" +fi + +# Select netmode +if [ "$NETMODE" ]; then + set_mode + /usr/bin/mmcli -m $SLOT --set-allowed-modes="$NMODE" --set-preferred-mode=$PREFMODE +else + /usr/bin/mmcli -m $SLOT --set-allowed-modes="4g|3g" --set-preferred-mode=4g +fi + diff --git a/root/usr/share/rpcd/acl.d/luci-app-mmconfig.json b/root/usr/share/rpcd/acl.d/luci-app-mmconfig.json new file mode 100644 index 0000000..c0e2414 --- /dev/null +++ b/root/usr/share/rpcd/acl.d/luci-app-mmconfig.json @@ -0,0 +1,11 @@ +{ + "luci-app-mmconfig": { + "description": "Grant UCI access for luci-app-mmconfig", + "read": { + "uci": [ "modemconfig" ] + }, + "write": { + "uci": [ "modemconfig" ] + } + } +} diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..bf2f39cf775be3f6de95e2de00d54c726975c0e0 GIT binary patch literal 32963 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 r?xY_O%-9