From 14d771b90f5a7d3887e5e900d1fb4737477ad305 Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Wed, 5 Feb 2014 08:38:27 +0100 Subject: Imported Upstream version 0.5.2.0 --- ABOUT-NLS | 1068 ++++++++++++++++ Makefile.am | 5 +- Makefile.in | 13 +- NEWS | 21 + aclocal.m4 | 38 +- config.rpath | 666 ++++++++++ configure | 44 +- configure.ac | 15 +- introspection/Makefile.in | 2 +- .../org.freedesktop.ModemManager.Modem.Gsm.SMS.xml | 37 +- libqcdm/AUTHORS | 0 libqcdm/ChangeLog | 0 libqcdm/Makefile.in | 6 +- libqcdm/NEWS | 0 libqcdm/README | 0 libqcdm/src/Makefile.am | 5 +- libqcdm/src/Makefile.in | 21 +- libqcdm/src/com.c | 21 +- libqcdm/src/com.h | 4 +- libqcdm/src/commands.c | 1272 +++++++++++++------- libqcdm/src/commands.h | 370 +++--- libqcdm/src/dm-commands.h | 368 ++++-- libqcdm/src/error.c | 88 -- libqcdm/src/error.h | 54 - libqcdm/src/errors.c | 60 + libqcdm/src/errors.h | 102 ++ libqcdm/src/log-items.h | 161 +++ libqcdm/src/nv-items.h | 34 +- libqcdm/src/result-private.h | 38 +- libqcdm/src/result.c | 509 +++++--- libqcdm/src/result.h | 31 +- libqcdm/src/utils.c | 91 +- libqcdm/src/utils.h | 53 +- libqcdm/tests/Makefile.am | 18 +- libqcdm/tests/Makefile.in | 72 +- libqcdm/tests/test-qcdm-com.c | 710 ++++++++--- libqcdm/tests/test-qcdm-com.h | 6 + libqcdm/tests/test-qcdm-escaping.c | 2 +- libqcdm/tests/test-qcdm-result.c | 32 +- libqcdm/tests/test-qcdm-result.h | 1 + libqcdm/tests/test-qcdm-utils.c | 4 +- libqcdm/tests/test-qcdm.c | 4 + m4/compiler_warnings.m4 | 2 +- m4/nls.m4 | 31 + marshallers/Makefile.in | 2 +- plugins/77-mm-ericsson-mbm.rules | 27 + plugins/77-mm-nokia-port-types.rules | 39 + plugins/Makefile.am | 6 +- plugins/Makefile.in | 10 +- plugins/mm-modem-anydata-cdma.c | 6 + plugins/mm-modem-hso.c | 8 +- plugins/mm-modem-huawei-gsm.c | 99 +- plugins/mm-modem-mbm.c | 4 +- plugins/mm-modem-nokia.c | 9 + plugins/mm-modem-novatel-cdma.c | 16 +- plugins/mm-modem-novatel-gsm.c | 3 +- plugins/mm-modem-samsung-gsm.c | 4 +- plugins/mm-modem-sierra-gsm.c | 261 +++- plugins/mm-modem-wavecom-gsm.c | 121 +- plugins/mm-modem-x22x-gsm.c | 3 +- plugins/mm-modem-zte.c | 6 +- plugins/mm-plugin-huawei.c | 237 ++-- plugins/mm-plugin-longcheer.c | 3 +- plugins/mm-plugin-nokia.c | 33 +- plugins/mm-plugin-x22x.c | 3 +- policy/Makefile.in | 2 +- policy/org.freedesktop.modem-manager.policy | 2 +- policy/org.freedesktop.modem-manager.policy.in | 2 +- src/Makefile.in | 2 +- src/mm-at-serial-port.c | 83 +- src/mm-at-serial-port.h | 7 +- src/mm-charsets.c | 320 ++++- src/mm-charsets.h | 9 +- src/mm-errors.c | 141 +++ src/mm-errors.h | 39 + src/mm-generic-cdma.c | 67 +- src/mm-generic-gsm.c | 1228 ++++++++++++++++--- src/mm-generic-gsm.h | 11 +- src/mm-manager.c | 1 + src/mm-manager.h | 1 - src/mm-modem-base.c | 3 +- src/mm-modem-base.h | 1 - src/mm-modem-cdma.c | 2 + src/mm-modem-gsm-network.c | 2 + src/mm-modem-gsm-sms.c | 43 +- src/mm-modem-gsm-sms.h | 9 +- src/mm-modem-gsm-ussd.h | 4 +- src/mm-modem-helpers.c | 88 +- src/mm-modem.c | 4 + src/mm-plugin-base.c | 45 +- src/mm-plugin-base.h | 1 - src/mm-port.h | 1 - src/mm-qcdm-serial-port.c | 14 +- src/mm-qcdm-serial-port.h | 1 - src/mm-serial-parsers.c | 78 +- src/mm-serial-port.c | 17 + src/mm-serial-port.h | 1 - src/mm-sms-utils.c | 515 +++++++- src/mm-sms-utils.h | 24 + src/tests/Makefile.am | 16 +- src/tests/Makefile.in | 63 +- src/tests/test-at-serial-port.c | 86 ++ src/tests/test-charsets.c | 45 + src/tests/test-modem-helpers.c | 14 +- src/tests/test-qcdm-serial-port.c | 20 +- src/tests/test-sms.c | 289 ++++- test/Makefile.am | 7 +- test/Makefile.in | 9 +- test/disable.py | 5 +- test/enable.py | 5 +- test/info.py | 6 +- test/location.py | 5 +- test/mm-send-sms.py | 52 - test/scan.py | 89 ++ test/send-pin.py | 6 +- test/sms-get.py | 80 ++ test/sms-send.py | 89 ++ test/ussd.py | 48 + 118 files changed, 8470 insertions(+), 2211 deletions(-) create mode 100644 ABOUT-NLS create mode 100755 config.rpath create mode 100644 libqcdm/AUTHORS create mode 100644 libqcdm/ChangeLog create mode 100644 libqcdm/NEWS create mode 100644 libqcdm/README delete mode 100644 libqcdm/src/error.c delete mode 100644 libqcdm/src/error.h create mode 100644 libqcdm/src/errors.c create mode 100644 libqcdm/src/errors.h create mode 100644 libqcdm/src/log-items.h create mode 100644 m4/nls.m4 create mode 100644 plugins/77-mm-nokia-port-types.rules create mode 100644 src/tests/test-at-serial-port.c delete mode 100755 test/mm-send-sms.py create mode 100755 test/scan.py create mode 100755 test/sms-get.py create mode 100755 test/sms-send.py create mode 100755 test/ussd.py diff --git a/ABOUT-NLS b/ABOUT-NLS new file mode 100644 index 0000000..83bc72e --- /dev/null +++ b/ABOUT-NLS @@ -0,0 +1,1068 @@ +1 Notes on the Free Translation Project +*************************************** + +Free software is going international! The Free Translation Project is +a way to get maintainers of free software, translators, and users all +together, so that free software will gradually become able to speak many +languages. A few packages already provide translations for their +messages. + + If you found this `ABOUT-NLS' file inside a distribution, you may +assume that the distributed package does use GNU `gettext' internally, +itself available at your nearest GNU archive site. But you do _not_ +need to install GNU `gettext' prior to configuring, installing or using +this package with messages translated. + + Installers will find here some useful hints. These notes also +explain how users should proceed for getting the programs to use the +available translations. They tell how people wanting to contribute and +work on translations can contact the appropriate team. + + When reporting bugs in the `intl/' directory or bugs which may be +related to internationalization, you should tell about the version of +`gettext' which is used. The information can be found in the +`intl/VERSION' file, in internationalized packages. + +1.1 Quick configuration advice +============================== + +If you want to exploit the full power of internationalization, you +should configure it using + + ./configure --with-included-gettext + +to force usage of internationalizing routines provided within this +package, despite the existence of internationalizing capabilities in the +operating system where this package is being installed. So far, only +the `gettext' implementation in the GNU C library version 2 provides as +many features (such as locale alias, message inheritance, automatic +charset conversion or plural form handling) as the implementation here. +It is also not possible to offer this additional functionality on top +of a `catgets' implementation. Future versions of GNU `gettext' will +very likely convey even more functionality. So it might be a good idea +to change to GNU `gettext' as soon as possible. + + So you need _not_ provide this option if you are using GNU libc 2 or +you have installed a recent copy of the GNU gettext package with the +included `libintl'. + +1.2 INSTALL Matters +=================== + +Some packages are "localizable" when properly installed; the programs +they contain can be made to speak your own native language. Most such +packages use GNU `gettext'. Other packages have their own ways to +internationalization, predating GNU `gettext'. + + By default, this package will be installed to allow translation of +messages. It will automatically detect whether the system already +provides the GNU `gettext' functions. If not, the included GNU +`gettext' library will be used. This library is wholly contained +within this package, usually in the `intl/' subdirectory, so prior +installation of the GNU `gettext' package is _not_ required. +Installers may use special options at configuration time for changing +the default behaviour. The commands: + + ./configure --with-included-gettext + ./configure --disable-nls + +will, respectively, bypass any pre-existing `gettext' to use the +internationalizing routines provided within this package, or else, +_totally_ disable translation of messages. + + When you already have GNU `gettext' installed on your system and run +configure without an option for your new package, `configure' will +probably detect the previously built and installed `libintl.a' file and +will decide to use this. This might not be desirable. You should use +the more recent version of the GNU `gettext' library. I.e. if the file +`intl/VERSION' shows that the library which comes with this package is +more recent, you should use + + ./configure --with-included-gettext + +to prevent auto-detection. + + The configuration process will not test for the `catgets' function +and therefore it will not be used. The reason is that even an +emulation of `gettext' on top of `catgets' could not provide all the +extensions of the GNU `gettext' library. + + Internationalized packages usually have many `po/LL.po' files, where +LL gives an ISO 639 two-letter code identifying the language. Unless +translations have been forbidden at `configure' time by using the +`--disable-nls' switch, all available translations are installed +together with the package. However, the environment variable `LINGUAS' +may be set, prior to configuration, to limit the installed set. +`LINGUAS' should then contain a space separated list of two-letter +codes, stating which languages are allowed. + +1.3 Using This Package +====================== + +As a user, if your language has been installed for this package, you +only have to set the `LANG' environment variable to the appropriate +`LL_CC' combination. If you happen to have the `LC_ALL' or some other +`LC_xxx' environment variables set, you should unset them before +setting `LANG', otherwise the setting of `LANG' will not have the +desired effect. Here `LL' is an ISO 639 two-letter language code, and +`CC' is an ISO 3166 two-letter country code. For example, let's +suppose that you speak German and live in Germany. At the shell +prompt, merely execute `setenv LANG de_DE' (in `csh'), +`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). +This can be done from your `.login' or `.profile' file, once and for +all. + + You might think that the country code specification is redundant. +But in fact, some languages have dialects in different countries. For +example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The +country code serves to distinguish the dialects. + + The locale naming convention of `LL_CC', with `LL' denoting the +language and `CC' denoting the country, is the one use on systems based +on GNU libc. On other systems, some variations of this scheme are +used, such as `LL' or `LL_CC.ENCODING'. You can get the list of +locales supported by your system for your language by running the +command `locale -a | grep '^LL''. + + Not all programs have translations for all languages. By default, an +English message is shown in place of a nonexistent translation. If you +understand other languages, you can set up a priority list of languages. +This is done through a different environment variable, called +`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' +for the purpose of message handling, but you still need to have `LANG' +set to the primary language; this is required by other parts of the +system libraries. For example, some Swedish users who would rather +read translations in German than English for when Swedish is not +available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. + + Special advice for Norwegian users: The language code for Norwegian +bokma*l changed from `no' to `nb' recently (in 2003). During the +transition period, while some message catalogs for this language are +installed under `nb' and some older ones under `no', it's recommended +for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and +older translations are used. + + In the `LANGUAGE' environment variable, but not in the `LANG' +environment variable, `LL_CC' combinations can be abbreviated as `LL' +to denote the language's main dialect. For example, `de' is equivalent +to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' +(Portuguese as spoken in Portugal) in this context. + +1.4 Translating Teams +===================== + +For the Free Translation Project to be a success, we need interested +people who like their own language and write it well, and who are also +able to synergize with other translators speaking the same language. +Each translation team has its own mailing list. The up-to-date list of +teams can be found at the Free Translation Project's homepage, +`http://translationproject.org/', in the "Teams" area. + + If you'd like to volunteer to _work_ at translating messages, you +should become a member of the translating team for your own language. +The subscribing address is _not_ the same as the list itself, it has +`-request' appended. For example, speakers of Swedish can send a +message to `sv-request@li.org', having this message body: + + subscribe + + Keep in mind that team members are expected to participate +_actively_ in translations, or at solving translational difficulties, +rather than merely lurking around. If your team does not exist yet and +you want to start one, or if you are unsure about what to do or how to +get started, please write to `coordinator@translationproject.org' to +reach the coordinator for all translator teams. + + The English team is special. It works at improving and uniformizing +the terminology in use. Proven linguistic skills are praised more than +programming skills, here. + +1.5 Available Packages +====================== + +Languages are not equally supported in all packages. The following +matrix shows the current state of internationalization, as of November +2007. The matrix shows, in regard of each package, for which languages +PO files have been submitted to translation coordination, with a +translation percentage of at least 50%. + + Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo + +----------------------------------------------------+ + Compendium | [] [] [] [] | + a2ps | [] [] [] [] [] | + aegis | () | + ant-phone | () | + anubis | [] | + ap-utils | | + aspell | [] [] [] [] [] | + bash | [] | + bfd | | + bibshelf | [] | + binutils | | + bison | [] [] | + bison-runtime | [] | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] [] | + console-tools | [] [] | + coreutils | [] [] [] [] | + cpio | | + cpplib | [] [] [] | + cryptonit | [] | + dialog | | + diffutils | [] [] [] [] [] [] | + doodle | [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] | + fetchmail | [] [] () [] [] | + findutils | [] | + findutils_stable | [] [] [] | + flex | [] [] [] | + fslint | | + gas | | + gawk | [] [] [] | + gcal | [] | + gcc | [] | + gettext-examples | [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] | + gettext-tools | [] [] | + gip | [] | + gliv | [] [] | + glunarclock | [] | + gmult | [] [] | + gnubiff | () | + gnucash | [] [] () () [] | + gnuedu | | + gnulib | [] | + gnunet | | + gnunet-gtk | | + gnutls | [] | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] | + gpe-conf | [] [] | + gpe-contacts | | + gpe-edit | [] | + gpe-filemanager | | + gpe-go | [] | + gpe-login | [] [] | + gpe-ownerinfo | [] [] | + gpe-package | | + gpe-sketchbook | [] [] | + gpe-su | [] [] | + gpe-taskmanager | [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | | + gphoto2 | [] [] [] [] | + gprof | [] [] | + gpsdrive | | + gramadoir | [] [] | + grep | [] [] | + gretl | () | + gsasl | | + gss | | + gst-plugins-bad | [] [] | + gst-plugins-base | [] [] | + gst-plugins-good | [] [] [] | + gst-plugins-ugly | [] [] | + gstreamer | [] [] [] [] [] [] [] | + gtick | () | + gtkam | [] [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] | + herrie | [] | + hylafax | | + idutils | [] [] | + indent | [] [] [] [] | + iso_15924 | | + iso_3166 | [] [] [] [] [] [] [] [] [] [] [] | + iso_3166_2 | | + iso_4217 | [] [] [] | + iso_639 | [] [] [] [] | + jpilot | [] | + jtag | | + jwhois | | + kbd | [] [] [] [] | + keytouch | [] [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | () | + ld | [] | + leafpad | [] [] [] [] [] | + libc | [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] | + libgpg-error | [] | + libgphoto2 | [] [] | + libgphoto2_port | [] [] | + libgsasl | | + libiconv | [] [] | + libidn | [] [] [] | + lifelines | [] () | + lilypond | [] | + lingoteach | | + lprng | | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailfromd | | + mailutils | [] | + make | [] [] | + man-db | [] [] [] | + minicom | [] [] [] | + nano | [] [] [] | + opcodes | [] | + parted | [] [] | + pilot-qof | | + popt | [] [] [] | + psmisc | [] | + pwdutils | | + qof | | + radius | [] | + recode | [] [] [] [] [] [] | + rpm | [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] [] | + sed | [] [] [] | + shared-mime-info | [] [] [] [] () [] [] [] | + sharutils | [] [] [] [] [] [] | + shishi | | + skencil | [] () | + solfege | | + soundtracker | [] [] | + sp | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] [] | + texinfo | [] [] [] | + tin | () () | + tuxpaint | [] [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + util-linux-ng | [] [] [] [] | + vorbis-tools | [] | + wastesedge | () | + wdiff | [] [] [] [] | + wget | [] [] [] | + xchat | [] [] [] [] [] [] [] | + xkeyboard-config | [] | + xpad | [] [] [] | + +----------------------------------------------------+ + af am ar az be bg bs ca cs cy da de el en en_GB eo + 6 0 2 1 8 26 2 40 48 2 56 88 15 1 15 18 + + es et eu fa fi fr ga gl gu he hi hr hu id is it + +--------------------------------------------------+ + Compendium | [] [] [] [] [] | + a2ps | [] [] [] () | + aegis | | + ant-phone | [] | + anubis | [] | + ap-utils | [] [] | + aspell | [] [] [] | + bash | [] | + bfd | [] [] | + bibshelf | [] [] [] | + binutils | [] [] [] | + bison | [] [] [] [] [] [] | + bison-runtime | [] [] [] [] [] | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] | + console-tools | | + coreutils | [] [] [] [] [] [] | + cpio | [] [] [] | + cpplib | [] [] | + cryptonit | [] | + dialog | [] [] [] | + diffutils | [] [] [] [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] [] | + enscript | [] [] [] | + fetchmail | [] | + findutils | [] [] [] | + findutils_stable | [] [] [] [] | + flex | [] [] [] | + fslint | | + gas | [] [] | + gawk | [] [] [] [] () | + gcal | [] [] | + gcc | [] | + gettext-examples | [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] | + gettext-tools | [] [] [] [] | + gip | [] [] [] [] | + gliv | () | + glunarclock | [] [] [] | + gmult | [] [] [] | + gnubiff | () () | + gnucash | () () () | + gnuedu | [] | + gnulib | [] [] [] | + gnunet | | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] [] [] | + gpe-conf | [] | + gpe-contacts | [] [] | + gpe-edit | [] [] [] [] | + gpe-filemanager | [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] [] [] [] | + gpe-package | [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] [] | + gpe-taskmanager | [] [] [] | + gpe-timesheet | [] [] [] [] | + gpe-today | [] [] [] [] | + gpe-todo | [] | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] [] [] | + gpsdrive | [] | + gramadoir | [] [] | + grep | [] [] [] | + gretl | [] [] [] () | + gsasl | [] [] | + gss | [] [] | + gst-plugins-bad | [] [] [] [] | + gst-plugins-base | [] [] [] [] | + gst-plugins-good | [] [] [] [] [] | + gst-plugins-ugly | [] [] [] [] | + gstreamer | [] [] [] | + gtick | [] [] [] | + gtkam | [] [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | + herrie | [] | + hylafax | | + idutils | [] [] [] [] [] | + indent | [] [] [] [] [] [] [] [] [] [] | + iso_15924 | [] | + iso_3166 | [] [] [] [] [] [] [] [] [] [] [] [] [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] [] [] [] | + iso_639 | [] [] [] [] [] [] | + jpilot | [] [] | + jtag | [] | + jwhois | [] [] [] [] [] | + kbd | [] [] | + keytouch | [] [] [] | + keytouch-editor | [] | + keytouch-keyboa... | [] [] | + latrine | [] [] | + ld | [] [] [] [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] [] [] | + libgpg-error | [] | + libgphoto2 | [] [] [] | + libgphoto2_port | [] [] | + libgsasl | [] [] | + libiconv | [] [] [] | + libidn | [] [] | + lifelines | () | + lilypond | [] [] [] | + lingoteach | [] [] [] | + lprng | | + lynx | [] [] [] | + m4 | [] [] [] [] | + mailfromd | | + mailutils | [] [] | + make | [] [] [] [] [] [] [] [] | + man-db | [] | + minicom | [] [] [] [] | + nano | [] [] [] [] [] [] [] | + opcodes | [] [] [] [] | + parted | [] [] [] | + pilot-qof | | + popt | [] [] [] [] | + psmisc | [] [] | + pwdutils | | + qof | [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] [] | + rpm | [] [] | + screem | | + scrollkeeper | [] [] [] | + sed | [] [] [] [] [] | + shared-mime-info | [] [] [] [] [] [] | + sharutils | [] [] [] [] [] [] [] [] | + shishi | [] | + skencil | [] [] | + solfege | [] | + soundtracker | [] [] [] | + sp | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] [] [] [] [] | + texinfo | [] [] [] | + tin | [] () | + tuxpaint | [] [] | + unicode-han-tra... | | + unicode-transla... | [] [] | + util-linux | [] [] [] [] [] [] [] | + util-linux-ng | [] [] [] [] [] [] [] | + vorbis-tools | | + wastesedge | () | + wdiff | [] [] [] [] [] [] [] [] | + wget | [] [] [] [] [] [] [] [] | + xchat | [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] | + xpad | [] [] [] | + +--------------------------------------------------+ + es et eu fa fi fr ga gl gu he hi hr hu id is it + 85 22 14 2 48 101 61 12 2 8 2 6 53 29 1 52 + + ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn + +--------------------------------------------------+ + Compendium | [] | + a2ps | () [] [] | + aegis | () | + ant-phone | [] | + anubis | [] [] [] | + ap-utils | [] | + aspell | [] [] | + bash | [] | + bfd | | + bibshelf | [] | + binutils | | + bison | [] [] [] | + bison-runtime | [] [] [] | + bluez-pin | [] [] [] | + cflow | | + clisp | [] | + console-tools | | + coreutils | [] | + cpio | [] | + cpplib | [] | + cryptonit | [] | + dialog | [] [] | + diffutils | [] [] [] | + doodle | | + e2fsprogs | [] | + enscript | [] | + fetchmail | [] [] | + findutils | [] | + findutils_stable | [] | + flex | [] [] | + fslint | | + gas | | + gawk | [] [] | + gcal | | + gcc | | + gettext-examples | [] [] [] | + gettext-runtime | [] [] [] | + gettext-tools | [] [] | + gip | [] [] | + gliv | [] | + glunarclock | [] [] | + gmult | [] [] [] | + gnubiff | | + gnucash | () () () | + gnuedu | | + gnulib | [] [] | + gnunet | | + gnunet-gtk | | + gnutls | [] | + gpe-aerial | [] | + gpe-beam | [] | + gpe-calendar | [] | + gpe-clock | [] [] [] | + gpe-conf | [] [] [] | + gpe-contacts | [] | + gpe-edit | [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] | + gpe-taskmanager | [] [] [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | [] | + gphoto2 | [] [] | + gprof | [] | + gpsdrive | [] | + gramadoir | () | + grep | [] [] | + gretl | | + gsasl | [] | + gss | | + gst-plugins-bad | [] | + gst-plugins-base | [] | + gst-plugins-good | [] | + gst-plugins-ugly | [] | + gstreamer | [] | + gtick | [] | + gtkam | [] [] | + gtkorphan | [] | + gtkspell | [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] | + herrie | [] | + hylafax | | + idutils | [] | + indent | [] [] | + iso_15924 | [] | + iso_3166 | [] [] [] [] [] [] [] [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] | + iso_639 | [] [] [] [] | + jpilot | () () | + jtag | | + jwhois | [] | + kbd | [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | | + latrine | [] | + ld | | + leafpad | [] [] | + libc | [] [] [] | + libexif | | + libextractor | | + libgpewidget | [] | + libgpg-error | | + libgphoto2 | [] | + libgphoto2_port | [] | + libgsasl | [] | + libiconv | [] | + libidn | [] [] | + lifelines | [] | + lilypond | [] | + lingoteach | [] | + lprng | | + lynx | [] [] | + m4 | [] [] | + mailfromd | | + mailutils | | + make | [] [] [] | + man-db | | + minicom | [] | + nano | [] [] [] | + opcodes | [] | + parted | [] [] | + pilot-qof | | + popt | [] [] [] | + psmisc | [] [] [] | + pwdutils | | + qof | | + radius | | + recode | [] | + rpm | [] [] | + screem | [] | + scrollkeeper | [] [] [] [] | + sed | [] [] | + shared-mime-info | [] [] [] [] [] [] [] | + sharutils | [] [] | + shishi | | + skencil | | + solfege | () () | + soundtracker | | + sp | () | + system-tools-ba... | [] [] [] [] | + tar | [] [] [] | + texinfo | [] [] | + tin | | + tuxpaint | () [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] | + util-linux-ng | [] [] | + vorbis-tools | | + wastesedge | [] | + wdiff | [] [] | + wget | [] [] | + xchat | [] [] [] [] | + xkeyboard-config | [] [] [] | + xpad | [] [] [] | + +--------------------------------------------------+ + ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn + 51 2 25 3 2 0 6 0 2 2 20 0 11 1 103 6 + + or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + +--------------------------------------------------+ + Compendium | [] [] [] [] [] | + a2ps | () [] [] [] [] [] [] | + aegis | () () | + ant-phone | [] [] | + anubis | [] [] [] | + ap-utils | () | + aspell | [] [] [] | + bash | [] [] | + bfd | | + bibshelf | [] | + binutils | [] [] | + bison | [] [] [] [] [] | + bison-runtime | [] [] [] [] [] | + bluez-pin | [] [] [] [] [] [] [] [] [] | + cflow | [] | + clisp | [] | + console-tools | [] | + coreutils | [] [] [] [] | + cpio | [] [] [] | + cpplib | [] | + cryptonit | [] [] | + dialog | [] | + diffutils | [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] [] | + fetchmail | [] [] [] | + findutils | [] [] [] | + findutils_stable | [] [] [] [] [] [] | + flex | [] [] [] [] [] | + fslint | [] | + gas | | + gawk | [] [] [] [] | + gcal | [] | + gcc | [] [] | + gettext-examples | [] [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] [] [] | + gettext-tools | [] [] [] [] [] [] [] | + gip | [] [] [] [] | + gliv | [] [] [] [] [] [] | + glunarclock | [] [] [] [] [] [] | + gmult | [] [] [] [] | + gnubiff | () [] | + gnucash | () [] | + gnuedu | | + gnulib | [] [] [] | + gnunet | | + gnunet-gtk | [] | + gnutls | [] [] | + gpe-aerial | [] [] [] [] [] [] [] | + gpe-beam | [] [] [] [] [] [] [] | + gpe-calendar | [] [] [] [] | + gpe-clock | [] [] [] [] [] [] [] [] | + gpe-conf | [] [] [] [] [] [] [] | + gpe-contacts | [] [] [] [] [] | + gpe-edit | [] [] [] [] [] [] [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] [] [] [] [] [] | + gpe-login | [] [] [] [] [] [] [] [] | + gpe-ownerinfo | [] [] [] [] [] [] [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] [] [] [] [] [] [] | + gpe-su | [] [] [] [] [] [] [] [] | + gpe-taskmanager | [] [] [] [] [] [] [] [] | + gpe-timesheet | [] [] [] [] [] [] [] [] | + gpe-today | [] [] [] [] [] [] [] [] | + gpe-todo | [] [] [] [] | + gphoto2 | [] [] [] [] [] [] | + gprof | [] [] [] | + gpsdrive | [] [] | + gramadoir | [] [] | + grep | [] [] [] [] | + gretl | [] [] [] | + gsasl | [] [] [] | + gss | [] [] [] [] | + gst-plugins-bad | [] [] [] | + gst-plugins-base | [] [] | + gst-plugins-good | [] [] | + gst-plugins-ugly | [] [] [] | + gstreamer | [] [] [] [] | + gtick | [] | + gtkam | [] [] [] [] [] | + gtkorphan | [] | + gtkspell | [] [] [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] | + herrie | [] [] [] | + hylafax | | + idutils | [] [] [] [] [] | + indent | [] [] [] [] [] [] [] | + iso_15924 | | + iso_3166 | [] [] [] [] [] [] [] [] [] [] [] [] [] | + iso_3166_2 | | + iso_4217 | [] [] [] [] [] [] [] | + iso_639 | [] [] [] [] [] [] [] | + jpilot | | + jtag | [] | + jwhois | [] [] [] [] | + kbd | [] [] [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | | + ld | [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] | + libexif | [] [] | + libextractor | [] [] | + libgpewidget | [] [] [] [] [] [] [] [] | + libgpg-error | [] [] [] | + libgphoto2 | [] | + libgphoto2_port | [] [] [] | + libgsasl | [] [] [] [] | + libiconv | [] [] [] | + libidn | [] [] () | + lifelines | [] [] | + lilypond | | + lingoteach | [] | + lprng | [] | + lynx | [] [] [] | + m4 | [] [] [] [] [] | + mailfromd | [] | + mailutils | [] [] [] | + make | [] [] [] [] | + man-db | [] [] [] [] | + minicom | [] [] [] [] [] | + nano | [] [] [] [] | + opcodes | [] [] | + parted | [] | + pilot-qof | | + popt | [] [] [] [] | + psmisc | [] [] | + pwdutils | [] [] | + qof | [] [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] | + rpm | [] [] [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] | + sed | [] [] [] [] [] [] [] [] [] | + shared-mime-info | [] [] [] [] [] [] | + sharutils | [] [] [] [] | + shishi | [] | + skencil | [] [] [] | + solfege | [] | + soundtracker | [] [] | + sp | | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] [] [] [] | + texinfo | [] [] [] [] | + tin | () | + tuxpaint | [] [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + util-linux-ng | [] [] [] [] | + vorbis-tools | [] | + wastesedge | | + wdiff | [] [] [] [] [] [] [] | + wget | [] [] [] [] | + xchat | [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] | + xpad | [] [] [] | + +--------------------------------------------------+ + or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + 0 5 77 31 53 4 58 72 3 45 46 9 45 122 3 + + tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + +---------------------------------------------------+ + Compendium | [] [] [] [] | 19 + a2ps | [] [] [] | 19 + aegis | [] | 1 + ant-phone | [] [] | 6 + anubis | [] [] [] | 11 + ap-utils | () [] | 4 + aspell | [] [] [] | 16 + bash | [] | 6 + bfd | | 2 + bibshelf | [] | 7 + binutils | [] [] [] [] | 9 + bison | [] [] [] [] | 20 + bison-runtime | [] [] [] [] | 18 + bluez-pin | [] [] [] [] [] [] | 28 + cflow | [] [] | 5 + clisp | | 9 + console-tools | [] [] | 5 + coreutils | [] [] [] | 18 + cpio | [] [] [] [] | 11 + cpplib | [] [] [] [] [] | 12 + cryptonit | [] | 6 + dialog | [] [] [] | 9 + diffutils | [] [] [] [] [] | 29 + doodle | [] | 6 + e2fsprogs | [] [] | 10 + enscript | [] [] [] | 16 + fetchmail | [] [] | 12 + findutils | [] [] [] | 11 + findutils_stable | [] [] [] [] | 18 + flex | [] [] | 15 + fslint | [] | 2 + gas | [] | 3 + gawk | [] [] [] | 16 + gcal | [] | 5 + gcc | [] [] [] | 7 + gettext-examples | [] [] [] [] [] [] | 29 + gettext-runtime | [] [] [] [] [] [] | 28 + gettext-tools | [] [] [] [] [] | 20 + gip | [] [] | 13 + gliv | [] [] | 11 + glunarclock | [] [] [] | 15 + gmult | [] [] [] [] | 16 + gnubiff | [] | 2 + gnucash | () [] | 5 + gnuedu | [] | 2 + gnulib | [] | 10 + gnunet | | 0 + gnunet-gtk | [] [] | 3 + gnutls | | 4 + gpe-aerial | [] [] | 14 + gpe-beam | [] [] | 14 + gpe-calendar | [] [] | 7 + gpe-clock | [] [] [] [] | 21 + gpe-conf | [] [] [] | 16 + gpe-contacts | [] [] | 10 + gpe-edit | [] [] [] [] [] | 22 + gpe-filemanager | [] [] | 7 + gpe-go | [] [] [] [] | 19 + gpe-login | [] [] [] [] [] | 21 + gpe-ownerinfo | [] [] [] [] | 21 + gpe-package | [] | 6 + gpe-sketchbook | [] [] | 16 + gpe-su | [] [] [] [] | 21 + gpe-taskmanager | [] [] [] [] | 21 + gpe-timesheet | [] [] [] [] | 18 + gpe-today | [] [] [] [] [] | 21 + gpe-todo | [] [] | 8 + gphoto2 | [] [] [] [] | 21 + gprof | [] [] | 13 + gpsdrive | [] | 5 + gramadoir | [] | 7 + grep | [] | 12 + gretl | | 6 + gsasl | [] [] [] | 9 + gss | [] | 7 + gst-plugins-bad | [] [] [] | 13 + gst-plugins-base | [] [] | 11 + gst-plugins-good | [] [] [] [] [] | 16 + gst-plugins-ugly | [] [] [] | 13 + gstreamer | [] [] [] | 18 + gtick | [] [] | 7 + gtkam | [] | 16 + gtkorphan | [] | 7 + gtkspell | [] [] [] [] [] [] | 27 + gutenprint | | 4 + hello | [] [] [] [] [] | 38 + herrie | [] [] | 8 + hylafax | | 0 + idutils | [] [] | 15 + indent | [] [] [] [] [] | 28 + iso_15924 | [] [] | 4 + iso_3166 | [] [] [] [] [] [] [] [] [] | 54 + iso_3166_2 | [] [] | 4 + iso_4217 | [] [] [] [] [] | 24 + iso_639 | [] [] [] [] [] | 26 + jpilot | [] [] [] [] | 7 + jtag | [] | 3 + jwhois | [] [] [] | 13 + kbd | [] [] [] | 13 + keytouch | [] | 8 + keytouch-editor | [] | 5 + keytouch-keyboa... | [] | 5 + latrine | [] [] | 5 + ld | [] [] [] [] | 10 + leafpad | [] [] [] [] [] | 24 + libc | [] [] [] | 19 + libexif | [] | 5 + libextractor | [] | 5 + libgpewidget | [] [] [] | 20 + libgpg-error | [] | 6 + libgphoto2 | [] [] | 9 + libgphoto2_port | [] [] [] | 11 + libgsasl | [] | 8 + libiconv | [] [] | 11 + libidn | [] [] | 11 + lifelines | | 4 + lilypond | [] | 6 + lingoteach | [] | 6 + lprng | [] | 2 + lynx | [] [] [] | 15 + m4 | [] [] [] | 18 + mailfromd | [] [] | 3 + mailutils | [] [] | 8 + make | [] [] [] | 20 + man-db | [] | 9 + minicom | [] | 14 + nano | [] [] [] | 20 + opcodes | [] [] | 10 + parted | [] [] [] | 11 + pilot-qof | [] | 1 + popt | [] [] [] [] | 18 + psmisc | [] [] | 10 + pwdutils | [] | 3 + qof | [] | 4 + radius | [] [] | 7 + recode | [] [] [] | 25 + rpm | [] [] [] [] | 13 + screem | [] | 2 + scrollkeeper | [] [] [] [] | 26 + sed | [] [] [] [] | 23 + shared-mime-info | [] [] [] | 29 + sharutils | [] [] [] | 23 + shishi | [] | 3 + skencil | [] | 7 + solfege | [] | 3 + soundtracker | [] [] | 9 + sp | [] | 3 + system-tools-ba... | [] [] [] [] [] [] [] | 38 + tar | [] [] [] | 17 + texinfo | [] [] [] | 15 + tin | | 1 + tuxpaint | [] [] [] | 19 + unicode-han-tra... | | 0 + unicode-transla... | | 2 + util-linux | [] [] [] | 20 + util-linux-ng | [] [] [] | 20 + vorbis-tools | [] [] | 4 + wastesedge | | 1 + wdiff | [] [] | 23 + wget | [] [] [] | 20 + xchat | [] [] [] [] | 29 + xkeyboard-config | [] [] [] | 14 + xpad | [] [] [] | 15 + +---------------------------------------------------+ + 76 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + 163 domains 0 3 1 74 51 0 143 21 1 57 7 45 0 2036 + + Some counters in the preceding matrix are higher than the number of +visible blocks let us expect. This is because a few extra PO files are +used for implementing regional variants of languages, or language +dialects. + + For a PO file in the matrix above to be effective, the package to +which it applies should also have been internationalized and +distributed as such by its maintainer. There might be an observable +lag between the mere existence a PO file and its wide availability in a +distribution. + + If November 2007 seems to be old, you may fetch a more recent copy +of this `ABOUT-NLS' file on most GNU archive sites. The most +up-to-date matrix with full percentage details can be found at +`http://translationproject.org/extra/matrix.html'. + +1.6 Using `gettext' in new packages +=================================== + +If you are writing a freely available program and want to +internationalize it you are welcome to use GNU `gettext' in your +package. Of course you have to respect the GNU Library General Public +License which covers the use of the GNU `gettext' library. This means +in particular that even non-free programs can use `libintl' as a shared +library, whereas only free software can use `libintl' as a static +library or use modified versions of `libintl'. + + Once the sources are changed appropriately and the setup can handle +the use of `gettext' the only thing missing are the translations. The +Free Translation Project is also available for packages which are not +developed inside the GNU project. Therefore the information given above +applies also for every other Free Software Project. Contact +`coordinator@translationproject.org' to make the `.pot' files available +to the translation teams. + diff --git a/Makefile.am b/Makefile.am index bcfca11..19289b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,10 +32,11 @@ dbusservice_DATA = org.freedesktop.ModemManager.conf dbusservice_file_polkit = org.freedesktop.ModemManager.conf.polkit dbusservice_file_nopolkit = org.freedesktop.ModemManager.conf.nopolkit -org.freedesktop.ModemManager.conf: if WITH_POLKIT +org.freedesktop.ModemManager.conf: $(top_srcdir)/$(dbusservice_file_polkit) cp -f $(top_srcdir)/$(dbusservice_file_polkit) $(dbusservice_DATA) else +org.freedesktop.ModemManager.conf: $(top_srcdir)/$(dbusservice_file_nopolkit) cp -f $(top_srcdir)/$(dbusservice_file_nopolkit) $(dbusservice_DATA) endif @@ -55,7 +56,7 @@ include/mm-modem.h: $(XMLS) introspection/all.xml header-generator.xsl $(edit) $< >$@ xmldir = $(datadir)/dbus-1/interfaces -xml_DATA = $(filter-out introspection/all.xml, $(XMLS)) +xml_DATA = $(filter-out introspection/all.xml introspection/org.freedesktop.DBus.Properties.xml, $(XMLS)) edit = @sed \ -e 's|@sbindir[@]|$(sbindir)|g' \ diff --git a/Makefile.in b/Makefile.in index 396c857..f3457bf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -39,15 +39,15 @@ host_triplet = @host@ subdir = . DIST_COMMON = README $(am__configure_deps) $(include_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ - $(srcdir)/config.h.in $(top_srcdir)/configure AUTHORS COPYING \ - ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \ - install-sh ltmain.sh missing + $(srcdir)/config.h.in $(top_srcdir)/configure ABOUT-NLS \ + AUTHORS COPYING ChangeLog INSTALL NEWS compile config.guess \ + config.rpath config.sub depcomp install-sh ltmain.sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ @@ -312,7 +312,7 @@ dbusactivation_in_files = org.freedesktop.ModemManager.service.in dbusactivation_DATA = $(dbusactivation_in_files:.service.in=.service) include_HEADERS = include/mm-modem.h xmldir = $(datadir)/dbus-1/interfaces -xml_DATA = $(filter-out introspection/all.xml, $(XMLS)) +xml_DATA = $(filter-out introspection/all.xml introspection/org.freedesktop.DBus.Properties.xml, $(XMLS)) edit = @sed \ -e 's|@sbindir[@]|$(sbindir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ @@ -939,8 +939,9 @@ uninstall-am: uninstall-dbusactivationDATA uninstall-dbusserviceDATA \ @WITH_DOCS_TRUE@all: $(GENERATED_FILES) -org.freedesktop.ModemManager.conf: +@WITH_POLKIT_TRUE@org.freedesktop.ModemManager.conf: $(top_srcdir)/$(dbusservice_file_polkit) @WITH_POLKIT_TRUE@ cp -f $(top_srcdir)/$(dbusservice_file_polkit) $(dbusservice_DATA) +@WITH_POLKIT_FALSE@org.freedesktop.ModemManager.conf: $(top_srcdir)/$(dbusservice_file_nopolkit) @WITH_POLKIT_FALSE@ cp -f $(top_srcdir)/$(dbusservice_file_nopolkit) $(dbusservice_DATA) include/mm-modem.h: $(XMLS) introspection/all.xml header-generator.xsl diff --git a/NEWS b/NEWS index c03ac4b..6b07a56 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,24 @@ +Overview of changes in ModemManager 0.5.2 +------------------------------------------ + +- Better detection of registration state when connecting +- Added support for more Ericsson modems +- Many memory leak fixes +- Ensure Gobi devices are driven by the gobi plugin +- Added multi-part SMS message support +- Better handling of requests when modem is disabled +- USSD fixes for Huawei devices +- Added support for Nokia Internet Sticks +- Fixed quirky response handling on some Cinterion modems +- Fixed CREG response handling on modems that include the RAC +- Skip sending power-up command if modem is already powered up +- Added support for Sierra Wireless devices using Icera chips (USB305, Lightning) +- Fixed sending SMS messages with modems that only support PDU mode +- Fix reading SMS messages in text mode +- Fix communication with some Nokia phones +- Retry sending SMS messages in PDU mode if an error occurs in text mode + + Overview of changes in ModemManager 0.5 ---------------------------------------- diff --git a/aclocal.m4 b/aclocal.m4 index 10c2278..05d55f4 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -260,6 +260,10 @@ msgstr "" [CATOBJEXT=.mo DATADIRNAME=lib]) ;; + *-*-openbsd*) + CATOBJEXT=.mo + DATADIRNAME=share + ;; *) CATOBJEXT=.mo DATADIRNAME=lib @@ -452,39 +456,6 @@ sed 's/^/| /' conftest.foo >&AS_MESSAGE_LOG_FD fi]) -# nls.m4 serial 5 (gettext-0.18) -dnl Copyright (C) 1995-2003, 2005-2006, 2008-2010 Free Software Foundation, -dnl Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper , 1995-2000. -dnl Bruno Haible , 2000-2003. - -AC_PREREQ([2.50]) - -AC_DEFUN([AM_NLS], -[ - AC_MSG_CHECKING([whether NLS is requested]) - dnl Default is enabled NLS - AC_ARG_ENABLE([nls], - [ --disable-nls do not use Native Language Support], - USE_NLS=$enableval, USE_NLS=yes) - AC_MSG_RESULT([$USE_NLS]) - AC_SUBST([USE_NLS]) -]) - # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # @@ -1699,3 +1670,4 @@ m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) +m4_include([m4/nls.m4]) diff --git a/config.rpath b/config.rpath new file mode 100755 index 0000000..c547c68 --- /dev/null +++ b/config.rpath @@ -0,0 +1,666 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2007 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | cygwin* | pw32* | os2*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix4* | aix5*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + library_names_spec='$libname.a' + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd1*) + ;; + freebsd* | dragonfly*) + case "$host_os" in + freebsd[123]*) + library_names_spec='$libname$shrext$versuffix' ;; + *) + library_names_spec='$libname$shrext' ;; + esac + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + nto-qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <. # @@ -570,8 +570,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='ModemManager' PACKAGE_TARNAME='ModemManager' -PACKAGE_VERSION='0.5' -PACKAGE_STRING='ModemManager 0.5' +PACKAGE_VERSION='0.5.2.0' +PACKAGE_STRING='ModemManager 0.5.2.0' PACKAGE_BUGREPORT='dcbw@redhat.com' PACKAGE_URL='' @@ -615,6 +615,8 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +QCDM_STANDALONE_FALSE +QCDM_STANDALONE_TRUE WITH_TESTS_FALSE WITH_TESTS_TRUE WITH_DOCS_FALSE @@ -1373,7 +1375,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures ModemManager 0.5 to adapt to many kinds of systems. +\`configure' configures ModemManager 0.5.2.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1443,7 +1445,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of ModemManager 0.5:";; + short | recursive ) echo "Configuration of ModemManager 0.5.2.0:";; esac cat <<\_ACEOF @@ -1574,7 +1576,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -ModemManager configure 0.5 +ModemManager configure 0.5.2.0 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -1943,7 +1945,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by ModemManager $as_me 0.5, which was +It was created by ModemManager $as_me 0.5.2.0, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2758,7 +2760,7 @@ fi # Define the identity of the package. PACKAGE='ModemManager' - VERSION='0.5' + VERSION='0.5.2.0' cat >>confdefs.h <<_ACEOF @@ -13068,6 +13070,8 @@ $as_echo "yes" >&6; } fi + + pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GUDEV" >&5 $as_echo_n "checking for GUDEV... " >&6; } @@ -13940,6 +13944,10 @@ else DATADIRNAME=lib fi + ;; + *-*-openbsd*) + CATOBJEXT=.mo + DATADIRNAME=share ;; *) CATOBJEXT=.mo @@ -14219,7 +14227,7 @@ $as_echo "yes" >&6; } for option in -Wshadow -Wmissing-declarations -Wmissing-prototypes \ -Wdeclaration-after-statement -Wstrict-prototypes \ -Wfloat-equal -Wno-unused-parameter -Wno-sign-compare \ - -fno-strict-aliasing; do + -fno-strict-aliasing -Wno-deprecated-declarations; do SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $option" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc understands $option" >&5 @@ -14273,6 +14281,16 @@ _ACEOF fi +# Not building protocol libs standalone + if test "yes" = "no"; then + QCDM_STANDALONE_TRUE= + QCDM_STANDALONE_FALSE='#' +else + QCDM_STANDALONE_TRUE='#' + QCDM_STANDALONE_FALSE= +fi + + ac_config_files="$ac_config_files Makefile marshallers/Makefile libqcdm/Makefile libqcdm/src/Makefile libqcdm/tests/Makefile src/Makefile src/tests/Makefile plugins/Makefile test/Makefile introspection/Makefile po/Makefile.in policy/Makefile" cat >confcache <<\_ACEOF @@ -14428,6 +14446,10 @@ if test -z "${WITH_TESTS_TRUE}" && test -z "${WITH_TESTS_FALSE}"; then as_fn_error $? "conditional \"WITH_TESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${QCDM_STANDALONE_TRUE}" && test -z "${QCDM_STANDALONE_FALSE}"; then + as_fn_error $? "conditional \"QCDM_STANDALONE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -14837,7 +14859,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by ModemManager $as_me 0.5, which was +This file was extended by ModemManager $as_me 0.5.2.0, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14903,7 +14925,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -ModemManager config.status 0.5 +ModemManager config.status 0.5.2.0 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 66357d5..d842422 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,14 @@ AC_PREREQ([2.60]) -AC_INIT([ModemManager],[0.5],[dcbw@redhat.com],[ModemManager]) +dnl The MM version number +m4_define([mm_major_version], [0]) +m4_define([mm_minor_version], [5]) +m4_define([mm_micro_version], [2]) +m4_define([mm_nano_version], [0]) +m4_define([mm_version], + [mm_major_version.mm_minor_version.mm_micro_version.mm_nano_version]) + +AC_INIT([ModemManager],[mm_version],[dcbw@redhat.com],[ModemManager]) AM_INIT_AUTOMAKE([1.9 subdir-objects tar-ustar no-dist-gzip dist-bzip2 -Wno-portability]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AM_MAINTAINER_MODE @@ -30,6 +38,8 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package]) IT_PROG_INTLTOOL([0.35.0]) PKG_CHECK_MODULES(MM, dbus-glib-1 >= 0.86 glib-2.0 >= 2.18 gmodule-2.0 gobject-2.0) +AC_SUBST(MM_CFLAGS) +AC_SUBST(MM_LIBS) PKG_CHECK_MODULES(GUDEV, gudev-1.0) AC_SUBST(GUDEV_CFLAGS) @@ -137,6 +147,9 @@ if ! test x"$ac_distver" = x""; then AC_DEFINE_UNQUOTED(MM_DIST_VERSION, "$ac_distver", [Define the distribution version string]) fi +# Not building protocol libs standalone +AM_CONDITIONAL(QCDM_STANDALONE, test "yes" = "no") + AC_CONFIG_FILES([ Makefile marshallers/Makefile diff --git a/introspection/Makefile.in b/introspection/Makefile.in index 03512bd..907f969 100644 --- a/introspection/Makefile.in +++ b/introspection/Makefile.in @@ -40,7 +40,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml index 15953b8..9aa96de 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml @@ -31,9 +31,10 @@ A dictionary containing SMS properties of the SMS specified by the given index. This dictionary may contain the following key/value pairs: number : string - Phone number (mandatory) - text : string - SMS text (mandatory) + text : string - SMS text (mandatory, empty if data cannot be decoded) + data : byte array - SMS user data (TP-UD) (mandatory) + data-coding-scheme: uint (0..255) - SMS user data coding scheme (TP-DCS) (mandatory) smsc : string - SMS service center number (optional) - validity : uint (0..255) - Specifies when the SMS expires in SMSC (optional) class : uint (0..3) - Message importance and location (optional) completed: boolean - Whether all message parts have been received or not (optional) index : uint - Index of message (for Get and Delete) (optional) @@ -75,15 +76,15 @@ - - SMS properties to save with the following key values: + + SMS properties to save with the following key values: - number : string - Phone number (mandatory) - text : string - SMS text (mandatory) - smsc : string - SMS service center number (optional) - validity : uint (0..255) - Specifies when the SMS expires in SMSC (optional) - class : uint (0..3) - Message importance and location (optional) - + number : string - Phone number (mandatory) + text : string - SMS text (mandatory) + smsc : string - SMS service center number (optional) + relative-validity : uint - Minutes until the SMS expires in SMSC (optional) + class : uint (0..3) - Message importance and location (optional) + @@ -92,15 +93,15 @@ - - SMS properties to save with the following key values: + + SMS properties to save with the following key values: - number : string - Phone number (mandatory) - text : string - SMS text (mandatory) - smsc : string - SMS service center number (optional) - validity : uint (0..255) - Specifies when the SMS expires in SMSC (optional) - class : uint (0..3) - Message importance and location (optional) - + number : string - Phone number (mandatory) + text : string - SMS text (mandatory) + smsc : string - SMS service center number (optional) + relative-validity : uint - Minutes until the SMS expires in SMSC (optional) + class : uint (0..3) - Message importance and location (optional) + diff --git a/libqcdm/AUTHORS b/libqcdm/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/libqcdm/ChangeLog b/libqcdm/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/libqcdm/Makefile.in b/libqcdm/Makefile.in index 87cee4c..7268ff6 100644 --- a/libqcdm/Makefile.in +++ b/libqcdm/Makefile.in @@ -34,14 +34,14 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = libqcdm -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in COPYING \ - INSTALL +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + AUTHORS COPYING ChangeLog INSTALL NEWS ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/libqcdm/NEWS b/libqcdm/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/libqcdm/README b/libqcdm/README new file mode 100644 index 0000000..e69de29 diff --git a/libqcdm/src/Makefile.am b/libqcdm/src/Makefile.am index f9451c6..9aa9500 100644 --- a/libqcdm/src/Makefile.am +++ b/libqcdm/src/Makefile.am @@ -7,12 +7,13 @@ libqcdm_la_CPPFLAGS = \ libqcdm_la_SOURCES = \ dm-commands.h \ nv-items.h \ + log-items.h \ com.c \ com.h \ commands.c \ commands.h \ - error.c \ - error.h \ + errors.c \ + errors.h \ result.c \ result.h \ result-private.h \ diff --git a/libqcdm/src/Makefile.in b/libqcdm/src/Makefile.in index 7dbe6b7..24eafbb 100644 --- a/libqcdm/src/Makefile.in +++ b/libqcdm/src/Makefile.in @@ -41,7 +41,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -58,7 +58,7 @@ am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libqcdm_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am_libqcdm_la_OBJECTS = libqcdm_la-com.lo libqcdm_la-commands.lo \ - libqcdm_la-error.lo libqcdm_la-result.lo libqcdm_la-utils.lo + libqcdm_la-errors.lo libqcdm_la-result.lo libqcdm_la-utils.lo libqcdm_la_OBJECTS = $(am_libqcdm_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -249,12 +249,13 @@ libqcdm_la_CPPFLAGS = \ libqcdm_la_SOURCES = \ dm-commands.h \ nv-items.h \ + log-items.h \ com.c \ com.h \ commands.c \ commands.h \ - error.c \ - error.h \ + errors.c \ + errors.h \ result.c \ result.h \ result-private.h \ @@ -334,7 +335,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcdm_la-com.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcdm_la-commands.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcdm_la-error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcdm_la-errors.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcdm_la-result.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcdm_la-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcdm_test_la-utils.Plo@am__quote@ @@ -390,13 +391,13 @@ libqcdm_la-commands.lo: commands.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcdm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqcdm_la-commands.lo `test -f 'commands.c' || echo '$(srcdir)/'`commands.c -libqcdm_la-error.lo: error.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcdm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqcdm_la-error.lo -MD -MP -MF $(DEPDIR)/libqcdm_la-error.Tpo -c -o libqcdm_la-error.lo `test -f 'error.c' || echo '$(srcdir)/'`error.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqcdm_la-error.Tpo $(DEPDIR)/libqcdm_la-error.Plo +libqcdm_la-errors.lo: errors.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcdm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqcdm_la-errors.lo -MD -MP -MF $(DEPDIR)/libqcdm_la-errors.Tpo -c -o libqcdm_la-errors.lo `test -f 'errors.c' || echo '$(srcdir)/'`errors.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqcdm_la-errors.Tpo $(DEPDIR)/libqcdm_la-errors.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='error.c' object='libqcdm_la-error.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='errors.c' object='libqcdm_la-errors.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcdm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqcdm_la-error.lo `test -f 'error.c' || echo '$(srcdir)/'`error.c +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcdm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqcdm_la-errors.lo `test -f 'errors.c' || echo '$(srcdir)/'`errors.c libqcdm_la-result.lo: result.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcdm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqcdm_la-result.lo -MD -MP -MF $(DEPDIR)/libqcdm_la-result.Tpo -c -o libqcdm_la-result.lo `test -f 'result.c' || echo '$(srcdir)/'`result.c diff --git a/libqcdm/src/com.c b/libqcdm/src/com.c index 353103a..ad50dd0 100644 --- a/libqcdm/src/com.c +++ b/libqcdm/src/com.c @@ -21,21 +21,18 @@ #include #include "com.h" -#include "error.h" +#include "errors.h" -gboolean -qcdm_port_setup (int fd, GError **error) +int +qcdm_port_setup (int fd) { struct termios stbuf; - g_type_init (); - errno = 0; memset (&stbuf, 0, sizeof (stbuf)); if (tcgetattr (fd, &stbuf) != 0) { - g_set_error (error, - QCDM_SERIAL_ERROR, QCDM_SERIAL_CONFIG_FAILED, - "tcgetattr() error: %d", errno); + qcdm_err (0, "tcgetattr() error: %d", errno); + return -QCDM_ERROR_SERIAL_CONFIG_FAILED; } stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB); @@ -50,12 +47,10 @@ qcdm_port_setup (int fd, GError **error) errno = 0; if (tcsetattr (fd, TCSANOW, &stbuf) < 0) { - g_set_error (error, - QCDM_SERIAL_ERROR, QCDM_SERIAL_CONFIG_FAILED, - "tcsetattr() error: %d", errno); - return FALSE; + qcdm_err (0, "tcgetattr() error: %d", errno); + return -QCDM_ERROR_SERIAL_CONFIG_FAILED; } - return TRUE; + return QCDM_SUCCESS; } diff --git a/libqcdm/src/com.h b/libqcdm/src/com.h index 97561d0..7c3e349 100644 --- a/libqcdm/src/com.h +++ b/libqcdm/src/com.h @@ -18,8 +18,8 @@ #ifndef LIBQCDM_COM_H #define LIBQCDM_COM_H -#include +#include "utils.h" -gboolean qcdm_port_setup (int fd, GError **error); +int qcdm_port_setup (int fd); #endif /* LIBQCDM_COM_H */ diff --git a/libqcdm/src/commands.c b/libqcdm/src/commands.c index 2d4b707..f906f1a 100644 --- a/libqcdm/src/commands.c +++ b/libqcdm/src/commands.c @@ -16,9 +16,11 @@ */ #include +#include +#include #include "commands.h" -#include "error.h" +#include "errors.h" #include "dm-commands.h" #include "nv-items.h" #include "result-private.h" @@ -27,8 +29,8 @@ /**********************************************************************/ -static guint8 -cdma_prev_to_qcdm (guint8 cdma) +static u_int8_t +cdma_prev_to_qcdm (u_int8_t cdma) { switch (cdma) { case CDMA_PREV_IS_95: @@ -51,8 +53,8 @@ cdma_prev_to_qcdm (guint8 cdma) return QCDM_CDMA_PREV_UNKNOWN; } -static guint8 -cdma_band_class_to_qcdm (guint8 cdma) +static u_int8_t +cdma_band_class_to_qcdm (u_int8_t cdma) { switch (cdma) { case CDMA_BAND_CLASS_0_CELLULAR_800: @@ -113,18 +115,21 @@ cdma_band_class_to_qcdm (guint8 cdma) * */ static char * -bin2hexstr (const guint8 *bytes, int len) +bin2hexstr (const u_int8_t *bytes, int len) { static char hex_digits[] = "0123456789abcdef"; char *result; int i; - gsize buflen = (len * 2) + 1; + size_t buflen = (len * 2) + 1; - g_return_val_if_fail (bytes != NULL, NULL); - g_return_val_if_fail (len > 0, NULL); - g_return_val_if_fail (len < 4096, NULL); /* Arbitrary limit */ + qcdm_return_val_if_fail (bytes != NULL, NULL); + qcdm_return_val_if_fail (len > 0, NULL); + qcdm_return_val_if_fail (len < 4096, NULL); /* Arbitrary limit */ + + result = calloc (1, buflen); + if (result == NULL) + return NULL; - result = g_malloc0 (buflen); for (i = 0; i < len; i++) { result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf]; result[2*i+1] = hex_digits[bytes[i] & 0xf]; @@ -135,88 +140,116 @@ bin2hexstr (const guint8 *bytes, int len) /**********************************************************************/ -static gboolean -check_command (const char *buf, gsize len, guint8 cmd, gsize min_len, GError **error) +static qcdmbool +check_command (const char *buf, size_t len, u_int8_t cmd, size_t min_len, int *out_error) { if (len < 1) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_MALFORMED_RESPONSE, - "DM command response malformed (must be at least 1 byte in length)"); + qcdm_err (0, "DM command response malformed (must be at least 1 byte in length)"); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_MALFORMED; return FALSE; } switch (buf[0]) { case DIAG_CMD_BAD_CMD: - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_COMMAND, - "DM command %d unknown or unimplemented by the device", - cmd); + qcdm_err (0, "DM command %d unknown or unimplemented by the device", cmd); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_BAD_COMMAND; return FALSE; case DIAG_CMD_BAD_PARM: - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "DM command %d contained invalid parameter", - cmd); + qcdm_err (0, "DM command %d contained invalid parameter", cmd); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_BAD_PARAMETER; return FALSE; case DIAG_CMD_BAD_LEN: - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_LENGTH, - "DM command %d was the wrong size", - cmd); + qcdm_err (0, "DM command %d was the wrong size", cmd); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_BAD_LENGTH; return FALSE; case DIAG_CMD_BAD_DEV: - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_NOT_ACCEPTED, - "DM command %d was not accepted by the device", - cmd); + qcdm_err (0, "DM command %d was not accepted by the device", cmd); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_NOT_ACCEPTED; return FALSE; case DIAG_CMD_BAD_MODE: - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_MODE, - "DM command %d not allowed in the current device mode", - cmd); + qcdm_err (0, "DM command %d not allowed in the current device mode", cmd); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_BAD_MODE; return FALSE; case DIAG_CMD_BAD_SPC_MODE: - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_SPC_LOCKED, - "DM command %d not allowed because the Service Programming Code is locked", - cmd); + qcdm_err (0, "DM command %d not allowed because the Service Programming Code is locked", cmd); + if (out_error) + *out_error = -QCDM_ERROR_SPC_LOCKED; return FALSE; default: break; } if (buf[0] != cmd) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_UNEXPECTED, - "Unexpected DM command response (expected %d, got %d)", - cmd, buf[0]); + qcdm_err (0, "Unexpected DM command response (expected %d, got %d)", cmd, buf[0]); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_UNEXPECTED; return FALSE; } if (len < min_len) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_LENGTH, - "DM command %d response not long enough (got %zu, expected " - "at least %zu).", cmd, len, min_len); + qcdm_err (0, "DM command %d response not long enough (got %zu, expected " + "at least %zu).", cmd, len, min_len); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_BAD_LENGTH; return FALSE; } return TRUE; } -static gboolean -check_nv_cmd (DMCmdNVReadWrite *cmd, guint16 nv_item, GError **error) +static int +nv_status_to_qcdm_error (u_int16_t status) +{ + switch (status) { + case DIAG_NV_STATUS_OK: + return QCDM_SUCCESS; + case DIAG_NV_STATUS_BUSY: + return -QCDM_ERROR_NV_ERROR_BUSY; + case DIAG_NV_STATUS_BAD_COMMAND: + return -QCDM_ERROR_NV_ERROR_BAD_COMMAND; + case DIAG_NV_STATUS_MEMORY_FULL: + return -QCDM_ERROR_NV_ERROR_MEMORY_FULL; + case DIAG_NV_STATUS_FAILED: + return -QCDM_ERROR_NV_ERROR_FAILED; + case DIAG_NV_STATUS_INACTIVE: + return -QCDM_ERROR_NV_ERROR_INACTIVE; + case DIAG_NV_STATUS_BAD_PARAMETER: + return -QCDM_ERROR_NV_ERROR_BAD_PARAMETER; + case DIAG_NV_STATUS_READ_ONLY: + return -QCDM_ERROR_NV_ERROR_READ_ONLY; + default: + return -QCDM_ERROR_NVCMD_FAILED; + } +} + +static qcdmbool +check_nv_cmd (DMCmdNVReadWrite *cmd, u_int16_t nv_item, int *out_error) { - guint16 cmd_item; + u_int16_t cmd_item; - g_return_val_if_fail (cmd != NULL, FALSE); - g_return_val_if_fail ((cmd->code == DIAG_CMD_NV_READ) || (cmd->code == DIAG_CMD_NV_WRITE), FALSE); + qcdm_return_val_if_fail (cmd != NULL, FALSE); + qcdm_return_val_if_fail ((cmd->code == DIAG_CMD_NV_READ) || (cmd->code == DIAG_CMD_NV_WRITE), FALSE); /* NV read/write have a status byte at the end */ if (cmd->status != 0) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_NVCMD_FAILED, - "The NV operation failed (status 0x%X).", - GUINT16_FROM_LE (cmd->status)); + qcdm_err (0, "The NV operation failed (status 0x%X).", le16toh (cmd->status)); + if (out_error) + *out_error = nv_status_to_qcdm_error (le16toh (cmd->status)); return FALSE; } - cmd_item = GUINT16_FROM_LE (cmd->nv_item); + cmd_item = le16toh (cmd->nv_item); if (cmd_item != nv_item) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_UNEXPECTED, - "Unexpected DM NV command response (expected item %d, got " - "item %d)", nv_item, cmd_item); + qcdm_err (0, "Unexpected DM NV command response (expected item %d, got " + "item %d)", nv_item, cmd_item); + if (out_error) + *out_error = -QCDM_ERROR_RESPONSE_UNEXPECTED; return FALSE; } @@ -225,14 +258,14 @@ check_nv_cmd (DMCmdNVReadWrite *cmd, guint16 nv_item, GError **error) /**********************************************************************/ -gsize -qcdm_cmd_version_info_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_version_info_new (char *buf, size_t len) { char cmdbuf[3]; DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_VERSION_INFO; @@ -240,42 +273,42 @@ qcdm_cmd_version_info_new (char *buf, gsize len, GError **error) return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_version_info_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_version_info_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdVersionInfoRsp *rsp = (DMCmdVersionInfoRsp *) buf; char tmp[12]; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_VERSION_INFO, sizeof (DMCmdVersionInfoRsp), error)) + if (!check_command (buf, len, DIAG_CMD_VERSION_INFO, sizeof (DMCmdVersionInfoRsp), out_error)) return NULL; result = qcdm_result_new (); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->comp_date) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->comp_date) <= sizeof (tmp)); memcpy (tmp, rsp->comp_date, sizeof (rsp->comp_date)); qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_COMP_DATE, tmp); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->comp_time) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->comp_time) <= sizeof (tmp)); memcpy (tmp, rsp->comp_time, sizeof (rsp->comp_time)); qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_COMP_TIME, tmp); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->rel_date) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->rel_date) <= sizeof (tmp)); memcpy (tmp, rsp->rel_date, sizeof (rsp->rel_date)); qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_RELEASE_DATE, tmp); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->rel_time) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->rel_time) <= sizeof (tmp)); memcpy (tmp, rsp->rel_time, sizeof (rsp->rel_time)); qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_RELEASE_TIME, tmp); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->model) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->model) <= sizeof (tmp)); memcpy (tmp, rsp->model, sizeof (rsp->model)); qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_MODEL, tmp); @@ -284,14 +317,14 @@ qcdm_cmd_version_info_result (const char *buf, gsize len, GError **error) /**********************************************************************/ -gsize -qcdm_cmd_esn_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_esn_new (char *buf, size_t len) { char cmdbuf[3]; DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_ESN; @@ -299,21 +332,19 @@ qcdm_cmd_esn_new (char *buf, gsize len, GError **error) return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_esn_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_esn_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdEsnRsp *rsp = (DMCmdEsnRsp *) buf; char *tmp; - guint8 swapped[4]; + u_int8_t swapped[4]; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_ESN, sizeof (DMCmdEsnRsp), error)) + if (!check_command (buf, len, DIAG_CMD_ESN, sizeof (DMCmdEsnRsp), out_error)) return NULL; - result = qcdm_result_new (); - /* Convert the ESN from binary to a hex string; it's LE so we have to * swap it to get the correct ordering. */ @@ -323,22 +354,25 @@ qcdm_cmd_esn_result (const char *buf, gsize len, GError **error) swapped[3] = rsp->esn[0]; tmp = bin2hexstr (&swapped[0], sizeof (swapped)); - qcdm_result_add_string (result, QCDM_CMD_ESN_ITEM_ESN, tmp); - g_free (tmp); + if (tmp != NULL) { + result = qcdm_result_new (); + qcdm_result_add_string (result, QCDM_CMD_ESN_ITEM_ESN, tmp); + free (tmp); + } return result; } /**********************************************************************/ -gsize -qcdm_cmd_cdma_status_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_cdma_status_new (char *buf, size_t len) { char cmdbuf[3]; DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_STATUS; @@ -346,18 +380,18 @@ qcdm_cmd_cdma_status_new (char *buf, gsize len, GError **error) return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_cdma_status_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_cdma_status_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdStatusRsp *rsp = (DMCmdStatusRsp *) buf; char *tmp; - guint8 swapped[4]; - guint32 tmp_num; + u_int8_t swapped[4]; + u_int32_t tmp_num; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_STATUS, sizeof (DMCmdStatusRsp), error)) + if (!check_command (buf, len, DIAG_CMD_STATUS, sizeof (DMCmdStatusRsp), out_error)) return NULL; result = qcdm_result_new (); @@ -372,44 +406,44 @@ qcdm_cmd_cdma_status_result (const char *buf, gsize len, GError **error) tmp = bin2hexstr (&swapped[0], sizeof (swapped)); qcdm_result_add_string (result, QCDM_CMD_CDMA_STATUS_ITEM_ESN, tmp); - g_free (tmp); + free (tmp); - tmp_num = (guint32) GUINT16_FROM_LE (rsp->rf_mode); - qcdm_result_add_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RF_MODE, tmp_num); + tmp_num = (u_int32_t) le16toh (rsp->rf_mode); + qcdm_result_add_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RF_MODE, tmp_num); - tmp_num = (guint32) GUINT16_FROM_LE (rsp->cdma_rx_state); - qcdm_result_add_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RX_STATE, tmp_num); + tmp_num = (u_int32_t) le16toh (rsp->cdma_rx_state); + qcdm_result_add_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RX_STATE, tmp_num); - tmp_num = (guint32) GUINT16_FROM_LE (rsp->entry_reason); - qcdm_result_add_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_ENTRY_REASON, tmp_num); + tmp_num = (u_int32_t) le16toh (rsp->entry_reason); + qcdm_result_add_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_ENTRY_REASON, tmp_num); - tmp_num = (guint32) GUINT16_FROM_LE (rsp->curr_chan); - qcdm_result_add_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_CURRENT_CHANNEL, tmp_num); + tmp_num = (u_int32_t) le16toh (rsp->curr_chan); + qcdm_result_add_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_CURRENT_CHANNEL, tmp_num); - qcdm_result_add_uint8 (result, QCDM_CMD_CDMA_STATUS_ITEM_CODE_CHANNEL, rsp->cdma_code_chan); + qcdm_result_add_u8 (result, QCDM_CMD_CDMA_STATUS_ITEM_CODE_CHANNEL, rsp->cdma_code_chan); - tmp_num = (guint32) GUINT16_FROM_LE (rsp->pilot_base); - qcdm_result_add_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_PILOT_BASE, tmp_num); + tmp_num = (u_int32_t) le16toh (rsp->pilot_base); + qcdm_result_add_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_PILOT_BASE, tmp_num); - tmp_num = (guint32) GUINT16_FROM_LE (rsp->sid); - qcdm_result_add_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_SID, tmp_num); + tmp_num = (u_int32_t) le16toh (rsp->sid); + qcdm_result_add_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_SID, tmp_num); - tmp_num = (guint32) GUINT16_FROM_LE (rsp->nid); - qcdm_result_add_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_NID, tmp_num); + tmp_num = (u_int32_t) le16toh (rsp->nid); + qcdm_result_add_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_NID, tmp_num); return result; } /**********************************************************************/ -gsize -qcdm_cmd_sw_version_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_sw_version_new (char *buf, size_t len) { char cmdbuf[3]; DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_SW_VERSION; @@ -417,32 +451,32 @@ qcdm_cmd_sw_version_new (char *buf, gsize len, GError **error) return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_sw_version_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_sw_version_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdSwVersionRsp *rsp = (DMCmdSwVersionRsp *) buf; - char tmp[25]; + char tmp[32]; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_SW_VERSION, sizeof (*rsp), error)) + if (!check_command (buf, len, DIAG_CMD_SW_VERSION, sizeof (*rsp), out_error)) return NULL; result = qcdm_result_new (); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->version) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->version) <= sizeof (tmp)); memcpy (tmp, rsp->version, sizeof (rsp->version)); qcdm_result_add_string (result, QCDM_CMD_SW_VERSION_ITEM_VERSION, tmp); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->comp_date) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->comp_date) <= sizeof (tmp)); memcpy (tmp, rsp->comp_date, sizeof (rsp->comp_date)); qcdm_result_add_string (result, QCDM_CMD_SW_VERSION_ITEM_COMP_DATE, tmp); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (rsp->comp_time) <= sizeof (tmp)); + qcdm_assert (sizeof (rsp->comp_time) <= sizeof (tmp)); memcpy (tmp, rsp->comp_time, sizeof (rsp->comp_time)); qcdm_result_add_string (result, QCDM_CMD_SW_VERSION_ITEM_COMP_TIME, tmp); @@ -451,14 +485,14 @@ qcdm_cmd_sw_version_result (const char *buf, gsize len, GError **error) /**********************************************************************/ -gsize -qcdm_cmd_status_snapshot_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_status_snapshot_new (char *buf, size_t len) { char cmdbuf[3]; DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_STATUS_SNAPSHOT; @@ -466,45 +500,45 @@ qcdm_cmd_status_snapshot_new (char *buf, gsize len, GError **error) return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -static guint8 -snapshot_state_to_qcdm (guint8 cdma_state) +static u_int8_t +snapshot_state_to_qcdm (u_int8_t cdma_state) { /* CDMA_STATUS_SNAPSHOT_STATE_* -> QCDM_STATUS_SNAPSHOT_STATE_* */ return cdma_state + 1; } -QCDMResult * -qcdm_cmd_status_snapshot_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_status_snapshot_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdStatusSnapshotRsp *rsp = (DMCmdStatusSnapshotRsp *) buf; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_STATUS_SNAPSHOT, sizeof (*rsp), error)) + if (!check_command (buf, len, DIAG_CMD_STATUS_SNAPSHOT, sizeof (*rsp), out_error)) return NULL; result = qcdm_result_new (); - qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BAND_CLASS, cdma_band_class_to_qcdm (rsp->band_class)); - qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BASE_STATION_PREV, cdma_prev_to_qcdm (rsp->prev)); - qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_MOBILE_PREV, cdma_prev_to_qcdm (rsp->mob_prev)); - qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_PREV_IN_USE, cdma_prev_to_qcdm (rsp->prev_in_use)); - qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE, snapshot_state_to_qcdm (rsp->state & 0xF)); + qcdm_result_add_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BAND_CLASS, cdma_band_class_to_qcdm (rsp->band_class)); + qcdm_result_add_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BASE_STATION_PREV, cdma_prev_to_qcdm (rsp->prev)); + qcdm_result_add_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_MOBILE_PREV, cdma_prev_to_qcdm (rsp->mob_prev)); + qcdm_result_add_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_PREV_IN_USE, cdma_prev_to_qcdm (rsp->prev_in_use)); + qcdm_result_add_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE, snapshot_state_to_qcdm (rsp->state & 0xF)); return result; } /**********************************************************************/ -gsize -qcdm_cmd_pilot_sets_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_pilot_sets_new (char *buf, size_t len) { char cmdbuf[3]; DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_PILOT_SETS; @@ -517,7 +551,7 @@ qcdm_cmd_pilot_sets_new (char *buf, gsize len, GError **error) #define PILOT_SETS_CMD_NEIGHBOR_SET "neighbor-set" static const char * -set_num_to_str (guint32 num) +set_num_to_str (u_int32_t num) { if (num == QCDM_CMD_PILOT_SETS_TYPE_ACTIVE) return PILOT_SETS_CMD_ACTIVE_SET; @@ -528,88 +562,92 @@ set_num_to_str (guint32 num) return NULL; } -QCDMResult * -qcdm_cmd_pilot_sets_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_pilot_sets_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdPilotSetsRsp *rsp = (DMCmdPilotSetsRsp *) buf; - GByteArray *array; - gsize sets_len; + size_t sets_len; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_PILOT_SETS, sizeof (DMCmdPilotSetsRsp), error)) + if (!check_command (buf, len, DIAG_CMD_PILOT_SETS, sizeof (DMCmdPilotSetsRsp), out_error)) return NULL; result = qcdm_result_new (); sets_len = rsp->active_count * sizeof (DMCmdPilotSetsSet); if (sets_len > 0) { - array = g_byte_array_sized_new (sets_len); - g_byte_array_append (array, (const guint8 *) &rsp->sets[0], sets_len); - qcdm_result_add_boxed (result, PILOT_SETS_CMD_ACTIVE_SET, G_TYPE_BYTE_ARRAY, array); + qcdm_result_add_u8_array (result, + PILOT_SETS_CMD_ACTIVE_SET, + (const u_int8_t *) &rsp->sets[0], + sets_len); } sets_len = rsp->candidate_count * sizeof (DMCmdPilotSetsSet); if (sets_len > 0) { - array = g_byte_array_sized_new (sets_len); - g_byte_array_append (array, (const guint8 *) &rsp->sets[rsp->active_count], sets_len); - qcdm_result_add_boxed (result, PILOT_SETS_CMD_CANDIDATE_SET, G_TYPE_BYTE_ARRAY, array); + qcdm_result_add_u8_array (result, + PILOT_SETS_CMD_ACTIVE_SET, + (const u_int8_t *) &rsp->sets[rsp->active_count], + sets_len); } sets_len = rsp->neighbor_count * sizeof (DMCmdPilotSetsSet); if (sets_len > 0) { - array = g_byte_array_sized_new (sets_len); - g_byte_array_append (array, (const guint8 *) &rsp->sets[rsp->active_count + rsp->candidate_count], sets_len); - qcdm_result_add_boxed (result, PILOT_SETS_CMD_NEIGHBOR_SET, G_TYPE_BYTE_ARRAY, array); + qcdm_result_add_u8_array (result, + PILOT_SETS_CMD_ACTIVE_SET, + (const u_int8_t *) &rsp->sets[rsp->active_count + rsp->candidate_count], + sets_len); } return result; } -gboolean -qcdm_cmd_pilot_sets_result_get_num (QCDMResult *result, - guint32 set_type, - guint32 *out_num) +qcdmbool +qcdm_cmd_pilot_sets_result_get_num (QcdmResult *result, + u_int32_t set_type, + u_int32_t *out_num) { const char *set_name; - GByteArray *array = NULL; + const u_int8_t *array = NULL; + size_t array_len = 0; - g_return_val_if_fail (result != NULL, FALSE); + qcdm_return_val_if_fail (result != NULL, FALSE); set_name = set_num_to_str (set_type); - g_return_val_if_fail (set_name != NULL, FALSE); + qcdm_return_val_if_fail (set_name != NULL, FALSE); - if (!qcdm_result_get_boxed (result, set_name, (gpointer) &array)) + if (!qcdm_result_get_u8_array (result, set_name, &array, &array_len)) return FALSE; - *out_num = array->len / sizeof (DMCmdPilotSetsSet); + *out_num = array_len / sizeof (DMCmdPilotSetsSet); return TRUE; } -gboolean -qcdm_cmd_pilot_sets_result_get_pilot (QCDMResult *result, - guint32 set_type, - guint32 num, - guint32 *out_pn_offset, - guint32 *out_ecio, +qcdmbool +qcdm_cmd_pilot_sets_result_get_pilot (QcdmResult *result, + u_int32_t set_type, + u_int32_t num, + u_int32_t *out_pn_offset, + u_int32_t *out_ecio, float *out_db) { const char *set_name; - GByteArray *array = NULL; DMCmdPilotSetsSet *set; + const u_int8_t *array = NULL; + size_t array_len = 0; - g_return_val_if_fail (result != NULL, FALSE); + qcdm_return_val_if_fail (result != NULL, FALSE); set_name = set_num_to_str (set_type); - g_return_val_if_fail (set_name != NULL, FALSE); + qcdm_return_val_if_fail (set_name != NULL, FALSE); - if (!qcdm_result_get_boxed (result, set_name, (gpointer) &array)) + if (!qcdm_result_get_u8_array (result, set_name, &array, &array_len)) return FALSE; - g_return_val_if_fail (num < array->len / sizeof (DMCmdPilotSetsSet), FALSE); + qcdm_return_val_if_fail (num < array_len / sizeof (DMCmdPilotSetsSet), FALSE); - set = (DMCmdPilotSetsSet *) &array->data[num * sizeof (DMCmdPilotSetsSet)]; + set = (DMCmdPilotSetsSet *) &array[num * sizeof (DMCmdPilotSetsSet)]; *out_pn_offset = set->pn_offset; *out_ecio = set->ecio; /* EC/IO is in units of -0.5 dB per the specs */ @@ -619,19 +657,19 @@ qcdm_cmd_pilot_sets_result_get_pilot (QCDMResult *result, /**********************************************************************/ -gsize -qcdm_cmd_nv_get_mdn_new (char *buf, gsize len, guint8 profile, GError **error) +size_t +qcdm_cmd_nv_get_mdn_new (char *buf, size_t len, u_int8_t profile) { char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; DMNVItemMdn *req; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_NV_READ; - cmd->nv_item = GUINT16_TO_LE (DIAG_NV_DIR_NUMBER); + cmd->nv_item = htole16 (DIAG_NV_DIR_NUMBER); req = (DMNVItemMdn *) &cmd->data[0]; req->profile = profile; @@ -639,30 +677,30 @@ qcdm_cmd_nv_get_mdn_new (char *buf, gsize len, guint8 profile, GError **error) return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nv_get_mdn_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nv_get_mdn_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdNVReadWrite *rsp = (DMCmdNVReadWrite *) buf; DMNVItemMdn *mdn; char tmp[11]; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), error)) + if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), out_error)) return NULL; - if (!check_nv_cmd (rsp, DIAG_NV_DIR_NUMBER, error)) + if (!check_nv_cmd (rsp, DIAG_NV_DIR_NUMBER, out_error)) return NULL; mdn = (DMNVItemMdn *) &rsp->data[0]; result = qcdm_result_new (); - qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_MDN_ITEM_PROFILE, mdn->profile); + qcdm_result_add_u8 (result, QCDM_CMD_NV_GET_MDN_ITEM_PROFILE, mdn->profile); memset (tmp, 0, sizeof (tmp)); - g_assert (sizeof (mdn->mdn) <= sizeof (tmp)); + qcdm_assert (sizeof (mdn->mdn) <= sizeof (tmp)); memcpy (tmp, mdn->mdn, sizeof (mdn->mdn)); qcdm_result_add_string (result, QCDM_CMD_NV_GET_MDN_ITEM_MDN, tmp); @@ -671,8 +709,8 @@ qcdm_cmd_nv_get_mdn_result (const char *buf, gsize len, GError **error) /**********************************************************************/ -static gboolean -roam_pref_validate (guint8 dm) +static qcdmbool +roam_pref_validate (u_int8_t dm) { if ( dm == DIAG_NV_ROAM_PREF_HOME_ONLY || dm == DIAG_NV_ROAM_PREF_ROAM_ONLY @@ -681,19 +719,19 @@ roam_pref_validate (guint8 dm) return FALSE; } -gsize -qcdm_cmd_nv_get_roam_pref_new (char *buf, gsize len, guint8 profile, GError **error) +size_t +qcdm_cmd_nv_get_roam_pref_new (char *buf, size_t len, u_int8_t profile) { char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; DMNVItemRoamPref *req; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_NV_READ; - cmd->nv_item = GUINT16_TO_LE (DIAG_NV_ROAM_PREF); + cmd->nv_item = htole16 (DIAG_NV_ROAM_PREF); req = (DMNVItemRoamPref *) &cmd->data[0]; req->profile = profile; @@ -701,60 +739,56 @@ qcdm_cmd_nv_get_roam_pref_new (char *buf, gsize len, guint8 profile, GError **er return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nv_get_roam_pref_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nv_get_roam_pref_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdNVReadWrite *rsp = (DMCmdNVReadWrite *) buf; DMNVItemRoamPref *roam; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), error)) + if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), out_error)) return NULL; - if (!check_nv_cmd (rsp, DIAG_NV_ROAM_PREF, error)) + if (!check_nv_cmd (rsp, DIAG_NV_ROAM_PREF, out_error)) return NULL; roam = (DMNVItemRoamPref *) &rsp->data[0]; if (!roam_pref_validate (roam->roam_pref)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Unknown roam preference 0x%X", - roam->roam_pref); + qcdm_err (0, "Unknown roam preference 0x%X", roam->roam_pref); return NULL; } result = qcdm_result_new (); - qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_ROAM_PREF_ITEM_PROFILE, roam->profile); - qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_ROAM_PREF_ITEM_ROAM_PREF, roam->roam_pref); + qcdm_result_add_u8 (result, QCDM_CMD_NV_GET_ROAM_PREF_ITEM_PROFILE, roam->profile); + qcdm_result_add_u8 (result, QCDM_CMD_NV_GET_ROAM_PREF_ITEM_ROAM_PREF, roam->roam_pref); return result; } -gsize +size_t qcdm_cmd_nv_set_roam_pref_new (char *buf, - gsize len, - guint8 profile, - guint8 roam_pref, - GError **error) + size_t len, + u_int8_t profile, + u_int8_t roam_pref) { char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; DMNVItemRoamPref *req; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); if (!roam_pref_validate (roam_pref)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Invalid roam preference %d", roam_pref); + qcdm_err (0, "Invalid roam preference %d", roam_pref); return 0; } memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_NV_WRITE; - cmd->nv_item = GUINT16_TO_LE (DIAG_NV_ROAM_PREF); + cmd->nv_item = htole16 (DIAG_NV_ROAM_PREF); req = (DMNVItemRoamPref *) &cmd->data[0]; req->profile = profile; @@ -763,15 +797,15 @@ qcdm_cmd_nv_set_roam_pref_new (char *buf, return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nv_set_roam_pref_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nv_set_roam_pref_result (const char *buf, size_t len, int *out_error) { - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), error)) + if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), out_error)) return NULL; - if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_ROAM_PREF, error)) + if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_ROAM_PREF, out_error)) return NULL; return qcdm_result_new (); @@ -779,29 +813,37 @@ qcdm_cmd_nv_set_roam_pref_result (const char *buf, gsize len, GError **error) /**********************************************************************/ -static gboolean -mode_pref_validate (guint8 dm) +static qcdmbool +mode_pref_validate (u_int8_t dm) { - if ( dm == DIAG_NV_MODE_PREF_1X_ONLY - || dm == DIAG_NV_MODE_PREF_HDR_ONLY - || dm == DIAG_NV_MODE_PREF_AUTO) + switch (dm) { + case DIAG_NV_MODE_PREF_DIGITAL: + case DIAG_NV_MODE_PREF_DIGITAL_ONLY: + case DIAG_NV_MODE_PREF_AUTO: + case DIAG_NV_MODE_PREF_1X_ONLY: + case DIAG_NV_MODE_PREF_HDR_ONLY: + case DIAG_NV_MODE_PREF_1X_HDR_ONLY: + case DIAG_NV_MODE_PREF_LTE_ONLY: + case DIAG_NV_MODE_PREF_1X_HDR_LTE_ONLY: return TRUE; - return FALSE; + default: + return FALSE; + } } -gsize -qcdm_cmd_nv_get_mode_pref_new (char *buf, gsize len, guint8 profile, GError **error) +size_t +qcdm_cmd_nv_get_mode_pref_new (char *buf, size_t len, u_int8_t profile) { char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; DMNVItemModePref *req; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_NV_READ; - cmd->nv_item = GUINT16_TO_LE (DIAG_NV_MODE_PREF); + cmd->nv_item = htole16 (DIAG_NV_MODE_PREF); req = (DMNVItemModePref *) &cmd->data[0]; req->profile = profile; @@ -809,60 +851,54 @@ qcdm_cmd_nv_get_mode_pref_new (char *buf, gsize len, guint8 profile, GError **er return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nv_get_mode_pref_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nv_get_mode_pref_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdNVReadWrite *rsp = (DMCmdNVReadWrite *) buf; DMNVItemModePref *mode; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), error)) + if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), out_error)) return NULL; - if (!check_nv_cmd (rsp, DIAG_NV_MODE_PREF, error)) + if (!check_nv_cmd (rsp, DIAG_NV_MODE_PREF, out_error)) return NULL; mode = (DMNVItemModePref *) &rsp->data[0]; - if (!mode_pref_validate (mode->mode_pref)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Unknown mode preference 0x%X", - mode->mode_pref); - return NULL; - } + if (!mode_pref_validate (mode->mode_pref)) + qcdm_warn (0, "Unknown mode preference 0x%X", mode->mode_pref); result = qcdm_result_new (); - qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_MODE_PREF_ITEM_PROFILE, mode->profile); - qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_MODE_PREF_ITEM_MODE_PREF, mode->mode_pref); + qcdm_result_add_u8 (result, QCDM_CMD_NV_GET_MODE_PREF_ITEM_PROFILE, mode->profile); + qcdm_result_add_u8 (result, QCDM_CMD_NV_GET_MODE_PREF_ITEM_MODE_PREF, mode->mode_pref); return result; } -gsize +size_t qcdm_cmd_nv_set_mode_pref_new (char *buf, - gsize len, - guint8 profile, - guint8 mode_pref, - GError **error) + size_t len, + u_int8_t profile, + u_int8_t mode_pref) { char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; DMNVItemModePref *req; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); if (!mode_pref_validate (mode_pref)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Invalid mode preference %d", mode_pref); + qcdm_err (0, "Invalid mode preference %d", mode_pref); return 0; } memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_NV_WRITE; - cmd->nv_item = GUINT16_TO_LE (DIAG_NV_MODE_PREF); + cmd->nv_item = htole16 (DIAG_NV_MODE_PREF); req = (DMNVItemModePref *) &cmd->data[0]; req->profile = profile; @@ -871,15 +907,15 @@ qcdm_cmd_nv_set_mode_pref_new (char *buf, return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nv_set_mode_pref_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nv_set_mode_pref_result (const char *buf, size_t len, int *out_error) { - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), error)) + if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), out_error)) return NULL; - if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_MODE_PREF, error)) + if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_MODE_PREF, out_error)) return NULL; return qcdm_result_new (); @@ -887,8 +923,8 @@ qcdm_cmd_nv_set_mode_pref_result (const char *buf, gsize len, GError **error) /**********************************************************************/ -static gboolean -hdr_rev_pref_validate (guint8 dm) +static qcdmbool +hdr_rev_pref_validate (u_int8_t dm) { if ( dm == DIAG_NV_HDR_REV_PREF_0 || dm == DIAG_NV_HDR_REV_PREF_A @@ -897,74 +933,70 @@ hdr_rev_pref_validate (guint8 dm) return FALSE; } -gsize -qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf, size_t len) { char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_NV_READ; - cmd->nv_item = GUINT16_TO_LE (DIAG_NV_HDR_REV_PREF); + cmd->nv_item = htole16 (DIAG_NV_HDR_REV_PREF); return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdNVReadWrite *rsp = (DMCmdNVReadWrite *) buf; DMNVItemHdrRevPref *rev; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), error)) + if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), out_error)) return NULL; - if (!check_nv_cmd (rsp, DIAG_NV_HDR_REV_PREF, error)) + if (!check_nv_cmd (rsp, DIAG_NV_HDR_REV_PREF, out_error)) return NULL; rev = (DMNVItemHdrRevPref *) &rsp->data[0]; if (!hdr_rev_pref_validate (rev->rev_pref)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Unknown HDR revision preference 0x%X", - rev->rev_pref); + qcdm_err (0, "Unknown HDR revision preference 0x%X", rev->rev_pref); return NULL; } result = qcdm_result_new (); - qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, rev->rev_pref); + qcdm_result_add_u8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, rev->rev_pref); return result; } -gsize +size_t qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf, - gsize len, - guint8 rev_pref, - GError **error) + size_t len, + u_int8_t rev_pref) { char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; DMNVItemHdrRevPref *req; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); if (!hdr_rev_pref_validate (rev_pref)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Invalid HDR revision preference %d", rev_pref); + qcdm_err (0, "Invalid HDR revision preference %d", rev_pref); return 0; } memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_NV_WRITE; - cmd->nv_item = GUINT16_TO_LE (DIAG_NV_HDR_REV_PREF); + cmd->nv_item = htole16 (DIAG_NV_HDR_REV_PREF); req = (DMNVItemHdrRevPref *) &cmd->data[0]; req->rev_pref = rev_pref; @@ -972,15 +1004,15 @@ qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf, return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, size_t len, int *out_error) { - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), error)) + if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), out_error)) return NULL; - if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_HDR_REV_PREF, error)) + if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_HDR_REV_PREF, out_error)) return NULL; return qcdm_result_new (); @@ -988,157 +1020,154 @@ qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, gsize len, GError **error) /**********************************************************************/ -gsize -qcdm_cmd_cm_subsys_state_info_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_cm_subsys_state_info_new (char *buf, size_t len) { char cmdbuf[sizeof (DMCmdSubsysHeader) + 2]; DMCmdSubsysHeader *cmd = (DMCmdSubsysHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_SUBSYS; cmd->subsys_id = DIAG_SUBSYS_CM; - cmd->subsys_cmd = GUINT16_TO_LE (DIAG_SUBSYS_CM_STATE_INFO); + cmd->subsys_cmd = htole16 (DIAG_SUBSYS_CM_STATE_INFO); return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_cm_subsys_state_info_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_cm_subsys_state_info_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdSubsysCMStateInfoRsp *rsp = (DMCmdSubsysCMStateInfoRsp *) buf; - guint32 tmp_num; - guint32 roam_pref; + u_int32_t tmp_num; + u_int32_t roam_pref; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysCMStateInfoRsp), error)) + if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysCMStateInfoRsp), out_error)) return NULL; - roam_pref = (guint32) GUINT32_FROM_LE (rsp->roam_pref); + roam_pref = (u_int32_t) le32toh (rsp->roam_pref); if (!roam_pref_validate (roam_pref)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Unknown roam preference 0x%X", - roam_pref); + qcdm_err (0, "Unknown roam preference 0x%X", roam_pref); return NULL; } result = qcdm_result_new (); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->call_state); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_CALL_STATE, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->call_state); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_CALL_STATE, tmp_num); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->oper_mode); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->oper_mode); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, tmp_num); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->system_mode); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->system_mode); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, tmp_num); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->mode_pref); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_MODE_PREF, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->mode_pref); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_MODE_PREF, tmp_num); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->band_pref); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_BAND_PREF, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->band_pref); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_BAND_PREF, tmp_num); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ROAM_PREF, roam_pref); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ROAM_PREF, roam_pref); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->srv_domain_pref); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SERVICE_DOMAIN_PREF, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->srv_domain_pref); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SERVICE_DOMAIN_PREF, tmp_num); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->acq_order_pref); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ACQ_ORDER_PREF, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->acq_order_pref); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ACQ_ORDER_PREF, tmp_num); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->hybrid_pref); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_HYBRID_PREF, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->hybrid_pref); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_HYBRID_PREF, tmp_num); - tmp_num = (guint32) GUINT32_FROM_LE (rsp->network_sel_mode_pref); - qcdm_result_add_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_NETWORK_SELECTION_PREF, tmp_num); + tmp_num = (u_int32_t) le32toh (rsp->network_sel_mode_pref); + qcdm_result_add_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_NETWORK_SELECTION_PREF, tmp_num); return result; } /**********************************************************************/ -gsize -qcdm_cmd_hdr_subsys_state_info_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_hdr_subsys_state_info_new (char *buf, size_t len) { char cmdbuf[sizeof (DMCmdSubsysHeader) + 2]; DMCmdSubsysHeader *cmd = (DMCmdSubsysHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_SUBSYS; cmd->subsys_id = DIAG_SUBSYS_HDR; - cmd->subsys_cmd = GUINT16_TO_LE (DIAG_SUBSYS_HDR_STATE_INFO); + cmd->subsys_cmd = htole16 (DIAG_SUBSYS_HDR_STATE_INFO); return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_hdr_subsys_state_info_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_hdr_subsys_state_info_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdSubsysHDRStateInfoRsp *rsp = (DMCmdSubsysHDRStateInfoRsp *) buf; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysHDRStateInfoRsp), error)) + if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysHDRStateInfoRsp), out_error)) return NULL; result = qcdm_result_new (); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_AT_STATE, rsp->at_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, rsp->session_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, rsp->almp_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_INIT_STATE, rsp->init_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_IDLE_STATE, rsp->idle_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_CONNECTED_STATE, rsp->connected_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ROUTE_UPDATE_STATE, rsp->route_update_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_OVERHEAD_MSG_STATE, rsp->overhead_msg_state); - qcdm_result_add_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, rsp->hdr_hybrid_mode); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_AT_STATE, rsp->at_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, rsp->session_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, rsp->almp_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_INIT_STATE, rsp->init_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_IDLE_STATE, rsp->idle_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_CONNECTED_STATE, rsp->connected_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ROUTE_UPDATE_STATE, rsp->route_update_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_OVERHEAD_MSG_STATE, rsp->overhead_msg_state); + qcdm_result_add_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, rsp->hdr_hybrid_mode); return result; } /**********************************************************************/ -gsize +size_t qcdm_cmd_ext_logmask_new (char *buf, - gsize len, - GSList *items, - guint16 maxlog, - GError **error) + size_t len, + u_int32_t items[], + u_int16_t maxlog) { char cmdbuf[sizeof (DMCmdExtLogMask) + 2]; DMCmdExtLogMask *cmd = (DMCmdExtLogMask *) &cmdbuf[0]; - GSList *iter; - guint16 highest = 0; - gsize total = 3; + u_int16_t highest = 0; + size_t total = 3; + u_int32_t i; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_EXT_LOGMASK; - for (iter = items; iter; iter = g_slist_next (iter)) { - guint32 item = GPOINTER_TO_UINT (iter->data); - - g_warn_if_fail (item > 0); - g_warn_if_fail (item < 4095); - cmd->mask[item / 8] |= 1 << item % 8; + if (items) { + for (i = 0; items[i] > 0; i++) { + qcdm_warn_if_fail (items[i] > 0); + qcdm_warn_if_fail (items[i] < 4095); + cmd->mask[items[i] / 8] |= 1 << items[i] % 8; - if (item > highest) - highest = item; + if (items[i] > highest) + highest = items[i]; + } } - g_return_val_if_fail (highest <= maxlog, 0); - cmd->len = GUINT16_TO_LE (maxlog); + qcdm_return_val_if_fail (highest <= maxlog, 0); + cmd->len = htole16 (maxlog); total += maxlog / 8; if (maxlog && maxlog % 8) total++; @@ -1146,23 +1175,20 @@ qcdm_cmd_ext_logmask_new (char *buf, return dm_encapsulate_buffer (cmdbuf, total, sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_ext_logmask_result (const char *buf, - gsize len, - GError **error) +QcdmResult * +qcdm_cmd_ext_logmask_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdExtLogMask *rsp = (DMCmdExtLogMask *) buf; - guint32 masklen = 0, maxlog = 0; - gsize minlen = 0; + u_int32_t masklen = 0, maxlog = 0; + size_t minlen = 0; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); /* Ensure size is at least enough for the command header */ if (len < 1) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_LENGTH, - "DM command %d response not long enough (got %zu, expected " - "at least %d).", DIAG_CMD_EXT_LOGMASK, len, 3); + qcdm_err (0, "DM command %d response not long enough (got %zu, expected " + "at least %d).", DIAG_CMD_EXT_LOGMASK, len, 3); return FALSE; } @@ -1175,48 +1201,47 @@ qcdm_cmd_ext_logmask_result (const char *buf, minlen = 1; else { /* Ensure size is equal to max # of log items + 3 */ - maxlog = GUINT16_FROM_LE (rsp->len); + maxlog = le16toh (rsp->len); masklen = maxlog / 8; if (maxlog % 8) masklen++; if (len < (masklen + 3)) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_LENGTH, - "DM command %d response not long enough (got %zu, expected " - "at least %d).", DIAG_CMD_EXT_LOGMASK, len, masklen + 3); + qcdm_err (0, "DM command %d response not long enough (got %zu, expected " + "at least %d).", DIAG_CMD_EXT_LOGMASK, len, masklen + 3); return FALSE; } minlen = masklen + 3; } - if (!check_command (buf, len, DIAG_CMD_EXT_LOGMASK, minlen, error)) + if (!check_command (buf, len, DIAG_CMD_EXT_LOGMASK, minlen, out_error)) return NULL; result = qcdm_result_new (); if (minlen != 4) - qcdm_result_add_uint32 (result, QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS, maxlog); + qcdm_result_add_u32 (result, QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS, maxlog); return result; } -gboolean -qcmd_cmd_ext_logmask_result_get_item (QCDMResult *result, - guint16 item) +qcdmbool +qcmd_cmd_ext_logmask_result_get_item (QcdmResult *result, + u_int16_t item) { return FALSE; } /**********************************************************************/ -gsize -qcdm_cmd_event_report_new (char *buf, gsize len, gboolean start, GError **error) +size_t +qcdm_cmd_event_report_new (char *buf, size_t len, qcdmbool start) { char cmdbuf[4]; DMCmdEventReport *cmd = (DMCmdEventReport *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_EVENT_REPORT; @@ -1225,12 +1250,12 @@ qcdm_cmd_event_report_new (char *buf, gsize len, gboolean start, GError **error) return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_event_report_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_event_report_result (const char *buf, size_t len, int *out_error) { - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_EVENT_REPORT, sizeof (DMCmdEventReport), error)) + if (!check_command (buf, len, DIAG_CMD_EVENT_REPORT, sizeof (DMCmdEventReport), out_error)) return NULL; return qcdm_result_new (); @@ -1238,60 +1263,57 @@ qcdm_cmd_event_report_result (const char *buf, gsize len, GError **error) /**********************************************************************/ -gsize -qcdm_cmd_zte_subsys_status_new (char *buf, gsize len, GError **error) +size_t +qcdm_cmd_zte_subsys_status_new (char *buf, size_t len) { char cmdbuf[sizeof (DMCmdSubsysHeader) + 2]; DMCmdSubsysHeader *cmd = (DMCmdSubsysHeader *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); memset (cmd, 0, sizeof (*cmd)); cmd->code = DIAG_CMD_SUBSYS; cmd->subsys_id = DIAG_SUBSYS_ZTE; - cmd->subsys_cmd = GUINT16_TO_LE (DIAG_SUBSYS_ZTE_STATUS); + cmd->subsys_cmd = htole16 (DIAG_SUBSYS_ZTE_STATUS); return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_zte_subsys_status_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_zte_subsys_status_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdSubsysZteStatusRsp *rsp = (DMCmdSubsysZteStatusRsp *) buf; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysZteStatusRsp), error)) + if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysZteStatusRsp), out_error)) return NULL; result = qcdm_result_new (); - qcdm_result_add_uint8 (result, QCDM_CMD_ZTE_SUBSYS_STATUS_ITEM_SIGNAL_INDICATOR, rsp->signal_ind); + qcdm_result_add_u8 (result, QCDM_CMD_ZTE_SUBSYS_STATUS_ITEM_SIGNAL_INDICATOR, rsp->signal_ind); return result; } /**********************************************************************/ -gsize +size_t qcdm_cmd_nw_subsys_modem_snapshot_cdma_new (char *buf, - gsize len, - guint8 chipset, - GError **error) + size_t len, + u_int8_t chipset) { char cmdbuf[sizeof (DMCmdSubsysNwSnapshotReq) + 2]; DMCmdSubsysNwSnapshotReq *cmd = (DMCmdSubsysNwSnapshotReq *) &cmdbuf[0]; - g_return_val_if_fail (buf != NULL, 0); - g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); /* Validate chipset */ if (chipset != QCDM_NW_CHIPSET_6500 && chipset != QCDM_NW_CHIPSET_6800) { - g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, - "Unknown Novatel chipset 0x%X", - chipset); + qcdm_err (0, "Unknown Novatel chipset 0x%X", chipset); return 0; } @@ -1305,43 +1327,43 @@ qcdm_cmd_nw_subsys_modem_snapshot_cdma_new (char *buf, cmd->hdr.subsys_id = DIAG_SUBSYS_NW_CONTROL_6800; break; default: - g_assert_not_reached (); + qcdm_assert_not_reached (); } - cmd->hdr.subsys_cmd = GUINT16_TO_LE (DIAG_SUBSYS_NW_CONTROL_MODEM_SNAPSHOT); + cmd->hdr.subsys_cmd = htole16 (DIAG_SUBSYS_NW_CONTROL_MODEM_SNAPSHOT); cmd->technology = DIAG_SUBSYS_NW_CONTROL_MODEM_SNAPSHOT_TECH_CDMA_EVDO; - cmd->snapshot_mask = GUINT32_TO_LE (0xFFFF); + cmd->snapshot_mask = htole32 (0xFFFF); return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); } -QCDMResult * -qcdm_cmd_nw_subsys_modem_snapshot_cdma_result (const char *buf, gsize len, GError **error) +QcdmResult * +qcdm_cmd_nw_subsys_modem_snapshot_cdma_result (const char *buf, size_t len, int *out_error) { - QCDMResult *result = NULL; + QcdmResult *result = NULL; DMCmdSubsysNwSnapshotRsp *rsp = (DMCmdSubsysNwSnapshotRsp *) buf; DMCmdSubsysNwSnapshotCdma *cdma = (DMCmdSubsysNwSnapshotCdma *) &rsp->data; - guint32 num; - guint8 num8; + u_int32_t num; + u_int8_t num8; - g_return_val_if_fail (buf != NULL, NULL); + qcdm_return_val_if_fail (buf != NULL, NULL); - if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysNwSnapshotRsp), error)) + if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysNwSnapshotRsp), out_error)) return NULL; /* FIXME: check response_code when we know what it means */ result = qcdm_result_new (); - num = GUINT32_FROM_LE (cdma->rssi); - qcdm_result_add_uint32 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_RSSI, num); + num = le32toh (cdma->rssi); + qcdm_result_add_u32 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_RSSI, num); num8 = cdma_prev_to_qcdm (cdma->prev); - qcdm_result_add_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_PREV, num8); + qcdm_result_add_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_PREV, num8); num8 = cdma_band_class_to_qcdm (cdma->band_class); - qcdm_result_add_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_BAND_CLASS, num8); + qcdm_result_add_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_BAND_CLASS, num8); - qcdm_result_add_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, cdma->eri); + qcdm_result_add_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, cdma->eri); num8 = QCDM_HDR_REV_UNKNOWN; switch (cdma->hdr_rev) { @@ -1354,7 +1376,393 @@ qcdm_cmd_nw_subsys_modem_snapshot_cdma_result (const char *buf, gsize len, GErro default: break; } - qcdm_result_add_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_HDR_REV, num8); + qcdm_result_add_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_HDR_REV, num8); + + return result; +} + +/**********************************************************************/ + +static size_t +qcdm_cmd_log_config_new (char *buf, + size_t len, + u_int32_t op, + u_int32_t equip_id, + u_int16_t items[]) +{ + DMCmdLogConfig *cmd; + u_int16_t highest = 0; + u_int32_t items_len = 0; + size_t cmdsize = 0, cmdbufsize; + u_int32_t i; + u_int16_t log_code; + + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail ((equip_id & 0xFFF0) == 0, 0); + + /* Find number of log items */ + if (items) { + while (items_len < 4095 && items[items_len]) { + /* Find highest log item so we can size the items mask */ + log_code = items[items_len] & 0x0FFF; + if (log_code > highest) + highest = log_code; + items_len++; + } + } + cmdsize = sizeof (DMCmdLogConfig) + ((highest + 7) / 8); + cmdbufsize = cmdsize + DIAG_TRAILER_LEN; + + qcdm_return_val_if_fail (len >= cmdsize, 0); + + cmd = calloc (1, cmdbufsize); + cmd->code = DIAG_CMD_LOG_CONFIG; + cmd->op = htole32 (op); + cmd->equipid = htole32 (equip_id); + + if (items) { + /* Set up the bitmask of log items */ + for (i = 0; i < items_len; i++) { + log_code = items[i] & 0x0FFF; /* Strip off equip ID */ + cmd->mask[log_code / 8] |= 1 << log_code % 8; + } + cmd->num_items = htole32 (highest); + } + + return dm_encapsulate_buffer ((char *) cmd, cmdsize, cmdbufsize, buf, len); +} + +size_t +qcdm_cmd_log_config_get_mask_new (char *buf, + size_t len, + u_int32_t equip_id) +{ + return qcdm_cmd_log_config_new (buf, + len, + DIAG_CMD_LOG_CONFIG_OP_GET_MASK, + equip_id, + NULL); +} + +static int +check_log_config_respose (const char *buf, size_t len, u_int32_t op) +{ + DMCmdLogConfigRsp *rsp = (DMCmdLogConfigRsp *) buf; + size_t minlen = 16; /* minimum valid resposne */ + int err; + + /* Ensure size is at least enough for the command header */ + if (len < 1) { + qcdm_err (0, "DIAG_CMD_LOG_CONFIG response not long enough (got %zu, " + "expected at least %d).", len, 3); + return -QCDM_ERROR_RESPONSE_BAD_LENGTH; + } + + if (rsp->code == DIAG_CMD_LOG_CONFIG) { + u_int32_t rspop; + + if (len < 16) { + /* At least enough for code + op + result + equipid */ + qcdm_err (0, "DIAG_CMD_LOG_CONFIG response not long enough (got %zu, " + "expected at least %d).", len, 16); + return -QCDM_ERROR_RESPONSE_BAD_LENGTH; + } + + rspop = le32toh (rsp->op); + if (rspop != op) { + qcdm_err (0, "DIAG_CMD_LOG_CONFIG response operation mismatch (got " + "op %u, expected %u)", rspop, op); + return -QCDM_ERROR_RESPONSE_BAD_COMMAND; + } + + /* check for success */ + if (le32toh (rsp->result) != 0) { + qcdm_err (0, "DIAG_CMD_LOG_CONFIG response failed with result %u.", + le32toh (rsp->result)); + return -QCDM_ERROR_RESPONSE_FAILED; + } + + switch (rspop) { + case DIAG_CMD_LOG_CONFIG_OP_GET_RANGE: + minlen += 16; /* get_range_items */ + break; + case DIAG_CMD_LOG_CONFIG_OP_SET_MASK: + case DIAG_CMD_LOG_CONFIG_OP_GET_MASK: + if (len < 16) { + qcdm_err (0, "DIAG_CMD_LOG_CONFIG response not long enough " + "(got %zu, expected at least %d).", len, 16); + return -QCDM_ERROR_RESPONSE_BAD_LENGTH; + } + minlen += 4; /* num_items */ + minlen += (le32toh (rsp->u.get_set_items.num_items) + 7) / 8; + break; + default: + qcdm_err (0, "Unknown DIAG_CMD_LOG_CONFIG response operation %d", rspop); + return -QCDM_ERROR_RESPONSE_UNEXPECTED; + } + } + + if (!check_command (buf, len, DIAG_CMD_LOG_CONFIG, minlen, &err)) + return err; + + return 0; +} + +#define LOG_CODE_SET(mask, code) (mask[code / 8] & (1 << (code % 8))) + +static QcdmResult * +log_config_get_set_result (const char *buf, size_t len, u_int32_t op, int *out_error) +{ + QcdmResult *result = NULL; + DMCmdLogConfigRsp *rsp = (DMCmdLogConfigRsp *) buf; + int err; + u_int32_t num_items; + u_int32_t equipid; + + qcdm_return_val_if_fail (buf != NULL, NULL); + + err = check_log_config_respose (buf, len, op); + if (err) { + if (out_error) + *out_error = err; + return NULL; + } + + result = qcdm_result_new (); + + equipid = le32toh (rsp->equipid); + qcdm_result_add_u32 (result, QCDM_CMD_LOG_CONFIG_MASK_ITEM_EQUIP_ID, equipid); + + num_items = le32toh (rsp->u.get_set_items.num_items); + qcdm_result_add_u32 (result, QCDM_CMD_LOG_CONFIG_MASK_ITEM_NUM_ITEMS, num_items); + + if (num_items > 0) { + u_int32_t i, num_result_items = 0, count = 0; + u_int16_t *items; + + /* First pass to find out how many are actually enabled */ + for (i = 0; i < num_items; i++) { + /* Check if the bit corresponding to this log item is set */ + if (LOG_CODE_SET (rsp->u.get_set_items.mask, i)) + num_result_items++; + } + + if (num_result_items) { + items = malloc (sizeof (*items) * num_result_items); + for (i = 0; i < num_items; i++) { + if (LOG_CODE_SET (rsp->u.get_set_items.mask, i)) + items[count++] = (equipid << 12) | (i & 0x0FFF); + } + + qcdm_result_add_u16_array (result, QCDM_CMD_LOG_CONFIG_MASK_ITEM_ITEMS, items, count); + free (items); + } + } + + return result; +} + +QcdmResult * +qcdm_cmd_log_config_get_mask_result (const char *buf, size_t len, int *out_error) +{ + return log_config_get_set_result (buf, len, DIAG_CMD_LOG_CONFIG_OP_GET_MASK, out_error); +} + +size_t +qcdm_cmd_log_config_set_mask_new (char *buf, + size_t len, + u_int32_t equip_id, + u_int16_t items[]) +{ + return qcdm_cmd_log_config_new (buf, + len, + DIAG_CMD_LOG_CONFIG_OP_SET_MASK, + equip_id, + items); +} + +QcdmResult * +qcdm_cmd_log_config_set_mask_result (const char *buf, size_t len, int *out_error) +{ + return log_config_get_set_result (buf, len, DIAG_CMD_LOG_CONFIG_OP_SET_MASK, out_error); +} + +qcdmbool +qcmd_cmd_log_config_mask_result_code_set (QcdmResult *result, + u_int32_t equipid, + u_int16_t log_code) +{ + const u_int16_t *items = NULL; + size_t len = 0; + u_int32_t i, tmp; + + qcdm_return_val_if_fail (result != NULL, FALSE); + + if (qcdm_result_get_u32 (result, QCDM_CMD_LOG_CONFIG_MASK_ITEM_EQUIP_ID, &tmp) != 0) + return FALSE; + qcdm_return_val_if_fail (equipid != tmp, FALSE); + + if (qcdm_result_get_u16_array (result, + QCDM_CMD_LOG_CONFIG_MASK_ITEM_ITEMS, + &items, + &len)) { + for (i = 0; i < len; i++) { + if ((items[i] & 0x0FFF) == (log_code & 0x0FFF)) + return TRUE; + } + } + return FALSE; +} + +/**********************************************************************/ + +static char bcd_chars[] = "0123456789\0\0\0\0\0\0"; + +static qcdmbool +imxi_bcd_to_string (u_int8_t bytes[8], size_t len, char *buf, size_t buflen) +{ + char *p; + u_int32_t i; + + if (bytes[0] == 0) + return TRUE; + + qcdm_return_val_if_fail (len == 8, FALSE); + qcdm_return_val_if_fail (buf != NULL, FALSE); + qcdm_return_val_if_fail (buflen > len, FALSE); + + p = buf; + for (i = 0 ; i < len; i++) { + /* IMxI are 15 chars long, so the lower 4-bits of the first + * byte of the IMxI is skipped. Not sure what it does. + */ + if (i > 0) { + *p = bcd_chars[bytes[i] & 0xf]; + if (!*p) + return FALSE; + p++; + } + *p = bcd_chars[(bytes[i] >> 4) & 0xf]; + if (!*p) + return FALSE; + p++; + } + *p++ = '\0'; + return TRUE; +} + +size_t +qcdm_cmd_wcdma_subsys_state_info_new (char *buf, size_t len) +{ + char cmdbuf[sizeof (DMCmdSubsysHeader) + 2]; + DMCmdSubsysHeader *cmd = (DMCmdSubsysHeader *) &cmdbuf[0]; + + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + + memset (cmd, 0, sizeof (*cmd)); + cmd->code = DIAG_CMD_SUBSYS; + cmd->subsys_id = DIAG_SUBSYS_WCDMA; + cmd->subsys_cmd = htole16 (DIAG_SUBSYS_WCDMA_STATE_INFO); + + return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); +} + +QcdmResult * +qcdm_cmd_wcdma_subsys_state_info_result (const char *buf, size_t len, int *out_error) +{ + QcdmResult *result = NULL; + DMCmdSubsysWcdmaStateInfoRsp *rsp = (DMCmdSubsysWcdmaStateInfoRsp *) buf; + char imxi[10]; + + qcdm_return_val_if_fail (buf != NULL, NULL); + + if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysWcdmaStateInfoRsp), out_error)) + return NULL; + + result = qcdm_result_new (); + + qcdm_result_add_u8 (result, QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_L1_STATE, rsp->l1_state); + + memset (imxi, 0, sizeof (imxi)); + if (imxi_bcd_to_string (rsp->imei, rsp->imei_len, imxi, sizeof (imxi))) + qcdm_result_add_string (result, QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_IMEI, imxi); + + memset (imxi, 0, sizeof (imxi)); + if (imxi_bcd_to_string (rsp->imsi, rsp->imsi_len, imxi, sizeof (imxi))) + qcdm_result_add_string (result, QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_IMSI, imxi); + + return result; +} + +/**********************************************************************/ + +size_t +qcdm_cmd_gsm_subsys_state_info_new (char *buf, size_t len) +{ + char cmdbuf[sizeof (DMCmdSubsysHeader) + 2]; + DMCmdSubsysHeader *cmd = (DMCmdSubsysHeader *) &cmdbuf[0]; + + qcdm_return_val_if_fail (buf != NULL, 0); + qcdm_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + + memset (cmd, 0, sizeof (*cmd)); + cmd->code = DIAG_CMD_SUBSYS; + cmd->subsys_id = DIAG_SUBSYS_GSM; + cmd->subsys_cmd = htole16 (DIAG_SUBSYS_GSM_STATE_INFO); + + return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); +} + +QcdmResult * +qcdm_cmd_gsm_subsys_state_info_result (const char *buf, size_t len, int *out_error) +{ + QcdmResult *result = NULL; + DMCmdSubsysGsmStateInfoRsp *rsp = (DMCmdSubsysGsmStateInfoRsp *) buf; + char imxi[10]; + u_int32_t mcc = 0, mnc = 0; + u_int8_t mnc3; + + qcdm_return_val_if_fail (buf != NULL, NULL); + + if (!check_command (buf, len, DIAG_CMD_SUBSYS, sizeof (DMCmdSubsysGsmStateInfoRsp), out_error)) + return NULL; + + result = qcdm_result_new (); + + memset (imxi, 0, sizeof (imxi)); + if (imxi_bcd_to_string (rsp->imei, rsp->imei_len, imxi, sizeof (imxi))) + qcdm_result_add_string (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_IMEI, imxi); + + memset (imxi, 0, sizeof (imxi)); + if (imxi_bcd_to_string (rsp->imsi, rsp->imsi_len, imxi, sizeof (imxi))) + qcdm_result_add_string (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_IMSI, imxi); + + qcdm_result_add_u8 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_CALL_STATE, rsp->cm_call_state); + qcdm_result_add_u8 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_OP_MODE, rsp->cm_opmode); + qcdm_result_add_u8 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_SYS_MODE, rsp->cm_sysmode); + + /* MCC/MNC, LAC, and CI don't seem to be valid when the modem is not in GSM mode */ + if ( rsp->cm_sysmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GSM + || rsp->cm_sysmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GW) { + /* Quick convert BCD LAI into MCC/MNC/LAC */ + mcc = (rsp->lai[0] & 0xF) * 100; + mcc += ((rsp->lai[0] >> 4) & 0xF) * 10; + mcc += rsp->lai[1] & 0xF; + qcdm_result_add_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_MCC, mcc); + + mnc = (rsp->lai[2] & 0XF) * 100; + mnc += ((rsp->lai[2] >> 4) & 0xF) * 10; + mnc3 = (rsp->lai[1] >> 4) & 0xF; + if (mnc3 != 0xF) + mnc += mnc3; + qcdm_result_add_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_MNC, mnc); + + qcdm_result_add_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_LAC, + le16toh (*(u_int16_t *)(&rsp->lai[3]))); + + qcdm_result_add_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CELLID, le16toh (rsp->cellid)); + } return result; } diff --git a/libqcdm/src/commands.h b/libqcdm/src/commands.h index bfacd56..6477eb1 100644 --- a/libqcdm/src/commands.h +++ b/libqcdm/src/commands.h @@ -18,8 +18,7 @@ #ifndef LIBQCDM_COMMANDS_H #define LIBQCDM_COMMANDS_H -#include - +#include "utils.h" #include "result.h" /**********************************************************************/ @@ -75,25 +74,21 @@ enum { #define QCDM_CMD_VERSION_INFO_ITEM_RELEASE_TIME "release-time" #define QCDM_CMD_VERSION_INFO_ITEM_MODEL "model" -gsize qcdm_cmd_version_info_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_version_info_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_version_info_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_version_info_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ #define QCDM_CMD_ESN_ITEM_ESN "esn" -gsize qcdm_cmd_esn_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_esn_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_esn_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_esn_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -127,13 +122,11 @@ enum { #define QCDM_CMD_CDMA_STATUS_ITEM_SID "sid" #define QCDM_CMD_CDMA_STATUS_ITEM_NID "nid" -gsize qcdm_cmd_cdma_status_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_cdma_status_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_cdma_status_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_cdma_status_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -145,13 +138,11 @@ QCDMResult *qcdm_cmd_cdma_status_result (const char *buf, #define QCDM_CMD_SW_VERSION_ITEM_COMP_DATE "comp-date" #define QCDM_CMD_SW_VERSION_ITEM_COMP_TIME "comp-time" -gsize qcdm_cmd_sw_version_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_sw_version_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_sw_version_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_sw_version_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -193,13 +184,11 @@ enum { /* The protocol revision currently in-use. One of QCDM_STATUS_SNAPSHOT_STATE_* */ #define QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE "state" -gsize qcdm_cmd_status_snapshot_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_status_snapshot_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_status_snapshot_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_status_snapshot_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -210,23 +199,21 @@ enum { QCDM_CMD_PILOT_SETS_TYPE_NEIGHBOR = 3, }; -gsize qcdm_cmd_pilot_sets_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_pilot_sets_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_pilot_sets_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_pilot_sets_result (const char *buf, + size_t len, + int *out_error); -gboolean qcdm_cmd_pilot_sets_result_get_num (QCDMResult *result, - guint32 set_type, - guint32 *out_num); +qcdmbool qcdm_cmd_pilot_sets_result_get_num (QcdmResult *result, + u_int32_t set_type, + u_int32_t *out_num); -gboolean qcdm_cmd_pilot_sets_result_get_pilot (QCDMResult *result, - guint32 set_type, - guint32 num, - guint32 *out_pn_offset, - guint32 *out_ecio, +qcdmbool qcdm_cmd_pilot_sets_result_get_pilot (QcdmResult *result, + u_int32_t set_type, + u_int32_t num, + u_int32_t *out_pn_offset, + u_int32_t *out_ecio, float *out_db); /**********************************************************************/ @@ -234,14 +221,11 @@ gboolean qcdm_cmd_pilot_sets_result_get_pilot (QCDMResult *result, #define QCDM_CMD_NV_GET_MDN_ITEM_PROFILE "profile" #define QCDM_CMD_NV_GET_MDN_ITEM_MDN "mdn" -gsize qcdm_cmd_nv_get_mdn_new (char *buf, - gsize len, - guint8 profile, - GError **error); +size_t qcdm_cmd_nv_get_mdn_new (char *buf, size_t len, u_int8_t profile); -QCDMResult *qcdm_cmd_nv_get_mdn_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_nv_get_mdn_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -255,55 +239,56 @@ enum { #define QCDM_CMD_NV_GET_ROAM_PREF_ITEM_PROFILE "profile" #define QCDM_CMD_NV_GET_ROAM_PREF_ITEM_ROAM_PREF "roam-pref" -gsize qcdm_cmd_nv_get_roam_pref_new (char *buf, - gsize len, - guint8 profile, - GError **error); +size_t qcdm_cmd_nv_get_roam_pref_new (char *buf, + size_t len, + u_int8_t profile); -QCDMResult *qcdm_cmd_nv_get_roam_pref_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_nv_get_roam_pref_result (const char *buf, + size_t len, + int *out_error); -gsize qcdm_cmd_nv_set_roam_pref_new (char *buf, - gsize len, - guint8 profile, - guint8 roam_pref, - GError **error); +size_t qcdm_cmd_nv_set_roam_pref_new (char *buf, + size_t len, + u_int8_t profile, + u_int8_t roam_pref); -QCDMResult *qcdm_cmd_nv_set_roam_pref_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_nv_set_roam_pref_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ /* Values for QCDM_CMD_NV_GET_MODE_PREF_ITEM_MODE_PREF */ enum { - QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_AUTO = 0x04, - QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_1X_ONLY = 0x09, - QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_HDR_ONLY = 0x0A, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_DIGITAL = 0x00, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_DIGITAL_ONLY = 0x01, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_AUTO = 0x04, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_1X_ONLY = 0x09, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_HDR_ONLY = 0x0A, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_1X_HDR_ONLY = 0x0D, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_LTE_ONLY = 0x1E, + QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_1X_HDR_LTE_ONLY = 0x24, }; #define QCDM_CMD_NV_GET_MODE_PREF_ITEM_PROFILE "profile" #define QCDM_CMD_NV_GET_MODE_PREF_ITEM_MODE_PREF "mode-pref" -gsize qcdm_cmd_nv_get_mode_pref_new (char *buf, - gsize len, - guint8 profile, - GError **error); +size_t qcdm_cmd_nv_get_mode_pref_new (char *buf, + size_t len, + u_int8_t profile); -QCDMResult *qcdm_cmd_nv_get_mode_pref_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_nv_get_mode_pref_result (const char *buf, + size_t len, + int *out_error); -gsize qcdm_cmd_nv_set_mode_pref_new (char *buf, - gsize len, - guint8 profile, - guint8 mode_pref, - GError **error); +size_t qcdm_cmd_nv_set_mode_pref_new (char *buf, + size_t len, + u_int8_t profile, + u_int8_t mode_pref); -QCDMResult *qcdm_cmd_nv_set_mode_pref_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_nv_set_mode_pref_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -316,28 +301,32 @@ enum { #define QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF "rev-pref" -gsize qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf, + size_t len, + int *out_error); -gsize qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf, - gsize len, - guint8 rev_pref, - GError **error); +size_t qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf, + size_t len, + u_int8_t rev_pref); -QCDMResult *qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ /* Values for QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE */ enum { - QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE = 5 + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_POWER_OFF = 0, + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_FIELD_TEST_MODE = 1, + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_OFFLINE = 2, + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_OFFLINE_AMPS = 3, + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_OFFLINE_CDMA = 4, + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE = 5, + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_LOW_POWER_MODE = 6, + QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_RESET = 7 }; /* Values for QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE */ @@ -354,6 +343,14 @@ enum { QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_LTE = 9, }; +enum { + QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_IDLE = 0, + QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_ORIGINATING = 1, + QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_ALERTING = 3, + QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_ORIGINATION_ALERTING = 4, + QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_CONVERSATION = 5, +}; + /* Values for QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ROAM_PREF */ enum { QCDM_CMD_CM_SUBSYS_STATE_INFO_ROAM_PREF_HOME_ONLY = 0x01, @@ -366,10 +363,18 @@ enum { /* Note: not the same values as QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF has; * AUTO really is 0x02 here, not 0x04 like the NV item value for AUTO. */ + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_AMPS_ONLY = 0x00, QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_DIGITAL_ONLY = 0x01, QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_AUTO = 0x02, + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_EMERGENCY = 0x03, QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_1X_ONLY = 0x09, QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_HDR_ONLY = 0x0A, + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_1X_AMPS_ONLY = 0x0B, + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_GPS_ONLY = 0x0C, + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_GSM_ONLY = 0x0D, + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_WCDMA_ONLY = 0x0E, + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_PERSISTENT_MODE = 0x0F, + QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_NO_CHANGE = 0x10, }; #define QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_CALL_STATE "call-state" @@ -383,13 +388,11 @@ enum { #define QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_HYBRID_PREF "hybrid-pref" #define QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_NETWORK_SELECTION_PREF "network-selection-pref" -gsize qcdm_cmd_cm_subsys_state_info_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_cm_subsys_state_info_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_cm_subsys_state_info_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_cm_subsys_state_info_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -468,55 +471,78 @@ enum { #define QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_OVERHEAD_MSG_STATE "overhead-msg-state" #define QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE "hdr-hybrid-mode" -gsize qcdm_cmd_hdr_subsys_state_info_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_hdr_subsys_state_info_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_hdr_subsys_state_info_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_hdr_subsys_state_info_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ /* Max # of log items this device supports */ #define QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS "max-items" -gsize qcdm_cmd_ext_logmask_new (char *buf, - gsize len, - GSList *items, - guint16 maxlog, - GError **error); +size_t qcdm_cmd_ext_logmask_new (char *buf, + size_t len, + u_int32_t items[], /* terminated by 0 */ + u_int16_t maxlog); -QCDMResult *qcdm_cmd_ext_logmask_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_ext_logmask_result (const char *buf, + size_t len, + int *out_error); /* Returns TRUE if 'item' is set in the log mask */ -gboolean qcmd_cmd_ext_logmask_result_get_item (QCDMResult *result, - guint16 item); +qcdmbool qcmd_cmd_ext_logmask_result_get_item (QcdmResult *result, + u_int16_t item); /**********************************************************************/ -gsize qcdm_cmd_event_report_new (char *buf, - gsize len, - gboolean start, - GError **error); +size_t qcdm_cmd_event_report_new (char *buf, + size_t len, + qcdmbool start); -QCDMResult *qcdm_cmd_event_report_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_event_report_result (const char *buf, + size_t len, + int *out_error); + +/**********************************************************************/ + +size_t qcdm_cmd_log_config_get_mask_new (char *buf, + size_t len, + u_int32_t equip_id); + +size_t qcdm_cmd_log_config_set_mask_new (char *buf, + size_t len, + u_int32_t equip_id, + u_int16_t items[]); + +#define QCDM_CMD_LOG_CONFIG_MASK_ITEM_EQUIP_ID "equip-id" + +#define QCDM_CMD_LOG_CONFIG_MASK_ITEM_NUM_ITEMS "num-items" + +#define QCDM_CMD_LOG_CONFIG_MASK_ITEM_ITEMS "items" + +QcdmResult *qcdm_cmd_log_config_get_mask_result (const char *buf, + size_t len, + int *out_error); + +QcdmResult *qcdm_cmd_log_config_set_mask_result (const char *buf, + size_t len, + int *out_error); + +qcdmbool qcmd_cmd_log_config_mask_result_code_set (QcdmResult *result, + u_int32_t equipid, + u_int16_t log_code); /**********************************************************************/ #define QCDM_CMD_ZTE_SUBSYS_STATUS_ITEM_SIGNAL_INDICATOR "signal-indicator" -gsize qcdm_cmd_zte_subsys_status_new (char *buf, - gsize len, - GError **error); +size_t qcdm_cmd_zte_subsys_status_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_zte_subsys_status_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_zte_subsys_status_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ @@ -539,14 +565,74 @@ enum { QCDM_NW_CHIPSET_6800 = 2, }; -gsize qcdm_cmd_nw_subsys_modem_snapshot_cdma_new (char *buf, - gsize len, - guint8 chipset, - GError **error); +size_t qcdm_cmd_nw_subsys_modem_snapshot_cdma_new (char *buf, + size_t len, + u_int8_t chipset); + +QcdmResult *qcdm_cmd_nw_subsys_modem_snapshot_cdma_result (const char *buf, + size_t len, + int *out_error); + +/**********************************************************************/ + +#define QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_IMEI "imei" + +#define QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_IMSI "imsi" + +/* Values for QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_L1_STATE */ + +enum { + QCDM_WCDMA_L1_STATE_INIT = 0, + QCDM_WCDMA_L1_STATE_IDLE = 1, + QCDM_WCDMA_L1_STATE_FS = 2, + QCDM_WCDMA_L1_STATE_ACQ = 3, + QCDM_WCDMA_L1_STATE_BCH = 4, + QCDM_WCDMA_L1_STATE_PCH = 5, + QCDM_WCDMA_L1_STATE_FACH = 6, + QCDM_WCDMA_L1_STATE_DCH = 7, + QCDM_WCDMA_L1_STATE_DEACTIVATE = 8, + QCDM_WCDMA_L1_STATE_DEEP_SLEEP = 9, + QCDM_WCDMA_L1_STATE_STOPPED = 10, + QCDM_WCDMA_L1_STATE_SUSPENDED = 11, +}; + +/* One of QCDM_WCDMA_L1_STATE_* */ +#define QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_L1_STATE "l1-state" + +size_t qcdm_cmd_wcdma_subsys_state_info_new (char *buf, size_t len); + +QcdmResult *qcdm_cmd_wcdma_subsys_state_info_result (const char *buf, + size_t len, + int *out_error); + +/**********************************************************************/ + +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_IMEI "imei" + +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_IMSI "imsi" + +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_MCC "lai-mcc" + +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_MNC "lai-mnc" + +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_LAC "lai-lac" + +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CELLID "cellid" + +/* One of QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_* */ +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_CALL_STATE "cm-call-state" + +/* One of QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_* */ +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_OP_MODE "cm-op-mode" + +/* One of QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_* */ +#define QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_SYS_MODE "cm-sys-mode" + +size_t qcdm_cmd_gsm_subsys_state_info_new (char *buf, size_t len); -QCDMResult *qcdm_cmd_nw_subsys_modem_snapshot_cdma_result (const char *buf, - gsize len, - GError **error); +QcdmResult *qcdm_cmd_gsm_subsys_state_info_result (const char *buf, + size_t len, + int *out_error); /**********************************************************************/ diff --git a/libqcdm/src/dm-commands.h b/libqcdm/src/dm-commands.h index d43f401..cc254bb 100644 --- a/libqcdm/src/dm-commands.h +++ b/libqcdm/src/dm-commands.h @@ -111,26 +111,49 @@ enum { DIAG_CMD_RAM_RW = 112, /* Calibration RAM control using DM */ DIAG_CMD_CPU_RW = 113, /* Calibration CPU control using DM */ DIAG_CMD_SET_FTM_TEST_MODE = 114, /* Field (or Factory?) Test Mode */ + DIAG_CMD_LOG_CONFIG = 115, /* New logging config command */ + DIAG_CMD_EXT_BUILD_ID = 124, + DIAG_CMD_EXT_MESSAGE_CONFIG= 125, + DIAG_CMD_EVENT_GET_MASK = 129, + DIAG_CMD_EVENT_SET_MASK = 130 }; /* Subsystem IDs used with DIAG_CMD_SUBSYS; these often obsolete many of * the original DM commands. */ enum { + DIAG_SUBSYS_WCDMA = 4, DIAG_SUBSYS_HDR = 5, /* High Data Rate (ie, EVDO) */ + DIAG_SUBSYS_GSM = 8, + DIAG_SUBSYS_UMTS = 9, + DIAG_SUBSYS_OS = 12, DIAG_SUBSYS_GPS = 13, - DIAG_SUBSYS_SMS = 14, + DIAG_SUBSYS_SMS = 14, /* Wireless Messaging Service */ DIAG_SUBSYS_CM = 15, /* Call manager */ + DIAG_SUBSYS_FS = 19, /* File System (EFS2) */ DIAG_SUBSYS_NW_CONTROL_6500 = 50, /* for Novatel Wireless MSM6500-based devices */ DIAG_SUBSYS_ZTE = 101, /* for ZTE EVDO devices */ DIAG_SUBSYS_NW_CONTROL_6800 = 250 /* for Novatel Wireless MSM6800-based devices */ }; +/* WCDMA subsystem command codes */ +enum { + DIAG_SUBSYS_WCDMA_CALL_START = 12, /* Starts a call */ + DIAG_SUBSYS_WCDMA_CALL_END = 13, /* Ends an ongoing call */ + DIAG_SUBSYS_WCDMA_STATE_INFO = 15, /* Gets WCDMA state */ +}; + /* HDR subsystem command codes */ enum { DIAG_SUBSYS_HDR_STATE_INFO = 8, /* Gets EVDO state */ }; +/* GSM subsystem command codes */ +enum { + DIAG_SUBSYS_GSM_STATE_INFO = 1, /* Gets GSM state */ +}; + +/* CM subsystem command codes */ enum { DIAG_SUBSYS_CM_STATE_INFO = 0, /* Gets Call Manager state */ }; @@ -211,140 +234,153 @@ enum { /* Generic DM command header */ struct DMCmdHeader { - guint8 code; + u_int8_t code; } __attribute__ ((packed)); typedef struct DMCmdHeader DMCmdHeader; /* DIAG_CMD_SUBSYS */ struct DMCmdSubsysHeader { - guint8 code; - guint8 subsys_id; - guint16 subsys_cmd; + u_int8_t code; + u_int8_t subsys_id; + u_int16_t subsys_cmd; } __attribute__ ((packed)); typedef struct DMCmdSubsysHeader DMCmdSubsysHeader; /* DIAG_CMD_NV_READ / DIAG_CMD_NV_WRITE */ struct DMCmdNVReadWrite { - guint8 code; - guint16 nv_item; - guint8 data[128]; - guint16 status; + u_int8_t code; + u_int16_t nv_item; + u_int8_t data[128]; + u_int16_t status; } __attribute__ ((packed)); typedef struct DMCmdNVReadWrite DMCmdNVReadWrite; /* DIAG_CMD_VERSION_INFO */ struct DMCmdVersionInfoRsp { - guint8 code; + u_int8_t code; char comp_date[11]; char comp_time[8]; char rel_date[11]; char rel_time[8]; char model[8]; - guint8 scm; - guint8 mob_cai_rev; - guint8 mob_model; - guint16 mob_firmware_rev; - guint8 slot_cycle_index; - guint8 msm_ver; - guint8 _unknown; + u_int8_t scm; + u_int8_t mob_cai_rev; + u_int8_t mob_model; + u_int16_t mob_firmware_rev; + u_int8_t slot_cycle_index; + u_int8_t msm_ver; + u_int8_t _unknown; } __attribute__ ((packed)); typedef struct DMCmdVersionInfoRsp DMCmdVersionInfoRsp; /* DIAG_CMD_ESN */ struct DMCmdEsnRsp { - guint8 code; - guint8 esn[4]; + u_int8_t code; + u_int8_t esn[4]; } __attribute__ ((packed)); typedef struct DMCmdEsnRsp DMCmdEsnRsp; /* DIAG_CMD_STATUS */ struct DMCmdStatusRsp { - guint8 code; - guint8 _unknown[3]; - guint8 esn[4]; - guint16 rf_mode; - guint8 min1_analog[4]; - guint8 min1_cdma[4]; - guint8 min2_analog[2]; - guint8 min2_cdma[2]; - guint8 _unknown1; - guint16 cdma_rx_state; - guint8 good_frames; - guint16 analog_corrected_frames; - guint16 analog_bad_frames; - guint16 analog_word_syncs; - guint16 entry_reason; - guint16 curr_chan; - guint8 cdma_code_chan; - guint16 pilot_base; - guint16 sid; - guint16 nid; - guint16 analog_locaid; - guint16 analog_rssi; - guint8 analog_power; + u_int8_t code; + u_int8_t _unknown[3]; + u_int8_t esn[4]; + u_int16_t rf_mode; + u_int8_t min1_analog[4]; + u_int8_t min1_cdma[4]; + u_int8_t min2_analog[2]; + u_int8_t min2_cdma[2]; + u_int8_t _unknown1; + u_int16_t cdma_rx_state; + u_int8_t good_frames; + u_int16_t analog_corrected_frames; + u_int16_t analog_bad_frames; + u_int16_t analog_word_syncs; + u_int16_t entry_reason; + u_int16_t curr_chan; + u_int8_t cdma_code_chan; + u_int16_t pilot_base; + u_int16_t sid; + u_int16_t nid; + u_int16_t analog_locaid; + u_int16_t analog_rssi; + u_int8_t analog_power; } __attribute__ ((packed)); typedef struct DMCmdStatusRsp DMCmdStatusRsp; /* DIAG_CMD_SW_VERSION */ struct DMCmdSwVersionRsp { - guint8 code; - char version[20]; + u_int8_t code; + char version[31]; char comp_date[11]; + u_int8_t _unknown1[2]; char comp_time[8]; + u_int8_t _unknown2[2]; } __attribute__ ((packed)); typedef struct DMCmdSwVersionRsp DMCmdSwVersionRsp; +typedef enum { + DM_OPER_MODE_POWER_OFF = 0, + DM_OPER_MODE_FIELD_TEST_MODE = 1, + DM_OPER_MODE_OFFLINE = 2, + DM_OPER_MODE_OFFLINE_AMPS = 3, + DM_OPER_MODE_OFFLINE_CDMA = 4, + DM_OPER_MODE_ONLINE = 5, + DM_OPER_MODE_LOW_POWER_MODE = 6, + DM_OPER_MODE_RESETTING = 7, +} DMOperMode; + /* DIAG_CMD_STATUS_SNAPSHOT */ struct DMCmdStatusSnapshotRsp { - guint8 code; - guint8 esn[4]; - guint8 imsi_s1[4]; - guint8 imsi_s2[2]; - guint8 imsi_s[8]; - guint8 imsi_11_12; - guint16 mcc; - guint8 imsi_addr_num; - guint16 sid; - guint16 nid; - guint8 prev; - guint8 prev_in_use; - guint8 mob_prev; - guint8 band_class; - guint16 frequency; - guint8 oper_mode; - guint8 state; - guint8 sub_state; + u_int8_t code; + u_int8_t esn[4]; + u_int8_t imsi_s1[4]; + u_int8_t imsi_s2[2]; + u_int8_t imsi_s[8]; + u_int8_t imsi_11_12; + u_int16_t mcc; + u_int8_t imsi_addr_num; + u_int16_t sid; + u_int16_t nid; + u_int8_t prev; + u_int8_t prev_in_use; + u_int8_t mob_prev; + u_int8_t band_class; + u_int16_t frequency; + u_int8_t oper_mode; + u_int8_t state; + u_int8_t sub_state; } __attribute__ ((packed)); typedef struct DMCmdStatusSnapshotRsp DMCmdStatusSnapshotRsp; /* DIAG_SUBSYS_CM_STATE_INFO subsys command */ struct DMCmdSubsysCMStateInfoRsp { DMCmdSubsysHeader header; - guint32 call_state; - guint32 oper_mode; - guint32 system_mode; - guint32 mode_pref; - guint32 band_pref; - guint32 roam_pref; - guint32 srv_domain_pref; - guint32 acq_order_pref; - guint32 hybrid_pref; - guint32 network_sel_mode_pref; + u_int32_t call_state; + u_int32_t oper_mode; + u_int32_t system_mode; + u_int32_t mode_pref; + u_int32_t band_pref; + u_int32_t roam_pref; + u_int32_t srv_domain_pref; + u_int32_t acq_order_pref; + u_int32_t hybrid_pref; + u_int32_t network_sel_mode_pref; } __attribute__ ((packed)); typedef struct DMCmdSubsysCMStateInfoRsp DMCmdSubsysCMStateInfoRsp; /* DIAG_SUBSYS_HDR_STATE_INFO subsys command */ struct DMCmdSubsysHDRStateInfoRsp { DMCmdSubsysHeader header; - guint8 at_state; - guint8 session_state; - guint8 almp_state; - guint8 init_state; - guint8 idle_state; - guint8 connected_state; - guint8 route_update_state; - guint8 overhead_msg_state; - guint8 hdr_hybrid_mode; + u_int8_t at_state; + u_int8_t session_state; + u_int8_t almp_state; + u_int8_t init_state; + u_int8_t idle_state; + u_int8_t connected_state; + u_int8_t route_update_state; + u_int8_t overhead_msg_state; + u_int8_t hdr_hybrid_mode; } __attribute__ ((packed)); typedef struct DMCmdSubsysHDRStateInfoRsp DMCmdSubsysHDRStateInfoRsp; @@ -352,94 +388,172 @@ typedef struct DMCmdSubsysHDRStateInfoRsp DMCmdSubsysHDRStateInfoRsp; /* DIAG_SUBSYS_ZTE_STATUS subsys command */ struct DMCmdSubsysZteStatusRsp { DMCmdSubsysHeader header; - guint8 _unknown1[8]; - guint8 signal_ind; - guint8 _unknown2; + u_int8_t _unknown1[8]; + u_int8_t signal_ind; + u_int8_t _unknown2; } __attribute__ ((packed)); typedef struct DMCmdSubsysZteStatusRsp DMCmdSubsysZteStatusRsp; /* DIAG_CMD_PILOT_SETS command */ struct DMCmdPilotSetsSet { - guint16 pn_offset; - guint16 ecio; + u_int16_t pn_offset; + u_int16_t ecio; } __attribute__ ((packed)); typedef struct DMCmdPilotSetsSet DMCmdPilotSetsSet; struct DMCmdPilotSetsRsp { - guint8 code; - guint16 pilot_inc; - guint8 active_count; - guint8 candidate_count; - guint8 neighbor_count; + u_int8_t code; + u_int16_t pilot_inc; + u_int8_t active_count; + u_int8_t candidate_count; + u_int8_t neighbor_count; DMCmdPilotSetsSet sets[52]; } __attribute__ ((packed)); typedef struct DMCmdPilotSetsRsp DMCmdPilotSetsRsp; +struct DMCmdLog { + u_int8_t code; + u_int8_t more; + u_int16_t len; + u_int16_t _unknown2; /* contains same value as len */ + u_int16_t log_code; + u_int64_t timestamp; + u_int8_t data[0]; +} __attribute__ ((packed)); +typedef struct DMCmdLog DMCmdLog; + struct DMCmdExtLogMask { - guint8 code; + u_int8_t code; /* Bit number of highest '1' in 'mask'; set to 0 to get current mask. */ - guint16 len; + u_int16_t len; /* Bitfield of log messages to receive */ - guint8 mask[512]; + u_int8_t mask[512]; } __attribute__ ((packed)); typedef struct DMCmdExtLogMask DMCmdExtLogMask; struct DMCmdEventReport { - guint8 code; - guint8 on; + u_int8_t code; + u_int8_t on; } __attribute__ ((packed)); typedef struct DMCmdEventReport DMCmdEventReport; struct DMCmdEventReportRsp { - guint8 code; - guint16 len; - guint16 event_id; - guint8 data[0]; + u_int8_t code; + u_int16_t len; + u_int16_t event_id; + u_int8_t data[0]; } __attribute__ ((packed)); typedef struct DMCmdEventReportRsp DMCmdEventReportRsp; /* DIAG_SUBSYS_NW_CONTROL_* subsys command */ struct DMCmdSubsysNwSnapshotReq { DMCmdSubsysHeader hdr; - guint8 technology; /* DIAG_SUBSYS_NW_CONTROL_MODEM_SNAPSHOT_TECH_* */ - guint32 snapshot_mask; + u_int8_t technology; /* DIAG_SUBSYS_NW_CONTROL_MODEM_SNAPSHOT_TECH_* */ + u_int32_t snapshot_mask; } __attribute__ ((packed)); typedef struct DMCmdSubsysNwSnapshotReq DMCmdSubsysNwSnapshotReq; /* DIAG_SUBSYS_NW_CONTROL_MODEM_SNAPSHOT response */ struct DMCmdSubsysNwSnapshotRsp { DMCmdSubsysHeader hdr; - guint8 response_code; - guint32 bitfield1; - guint32 bitfield2; - guint8 data[100]; + u_int8_t response_code; + u_int32_t bitfield1; + u_int32_t bitfield2; + u_int8_t data[100]; } __attribute__ ((packed)); typedef struct DMCmdSubsysNwSnapshotRsp DMCmdSubsysNwSnapshotRsp; struct DMCmdSubsysNwSnapshotCdma { - guint32 rssi; - guint32 battery_level; - guint8 call_info; - guint8 new_sms_ind; - guint8 missed_calls; - guint32 voicemail_ind; - guint8 pkt_call_ctrl_state; - guint8 mip_rrp_err_code; - guint8 cur_packet_zone_id; - guint8 prev; - guint8 band_class; - guint8 eri; - guint8 eri_alert_id; - guint32 cur_call_total_time; - guint32 cur_call_active_time; - guint32 cur_call_tx_ip_bytes; - guint32 cur_call_rx_ip_bytes; - guint8 connection_status; - guint16 dominant_pn; - guint8 wdisable_mask; - guint8 hdr_rev; + u_int32_t rssi; + u_int32_t battery_level; + u_int8_t call_info; + u_int8_t new_sms_ind; + u_int8_t missed_calls; + u_int32_t voicemail_ind; + u_int8_t pkt_call_ctrl_state; + u_int8_t mip_rrp_err_code; + u_int8_t cur_packet_zone_id; + u_int8_t prev; + u_int8_t band_class; + u_int8_t eri; + u_int8_t eri_alert_id; + u_int32_t cur_call_total_time; + u_int32_t cur_call_active_time; + u_int32_t cur_call_tx_ip_bytes; + u_int32_t cur_call_rx_ip_bytes; + u_int8_t connection_status; + u_int16_t dominant_pn; + u_int8_t wdisable_mask; + u_int8_t hdr_rev; } __attribute__ ((packed)); typedef struct DMCmdSubsysNwSnapshotCdma DMCmdSubsysNwSnapshotCdma; +enum { + DIAG_CMD_LOG_CONFIG_OP_GET_RANGE = 0x01, + DIAG_CMD_LOG_CONFIG_OP_SET_MASK = 0x03, + DIAG_CMD_LOG_CONFIG_OP_GET_MASK = 0x04, +}; + +struct DMCmdLogConfig { + u_int8_t code; + u_int8_t pad[3]; + u_int32_t op; + u_int32_t equipid; + u_int32_t num_items; + u_int8_t mask[0]; +} __attribute__ ((packed)); +typedef struct DMCmdLogConfig DMCmdLogConfig; + +struct DMCmdLogConfigRsp { + u_int8_t code; + u_int8_t pad[3]; + u_int32_t op; + u_int32_t result; /* 0 = success */ + u_int32_t equipid; + union { + u_int32_t get_range_items[16]; + struct { + u_int32_t num_items; + u_int8_t mask[0]; + } get_set_items; + } u; +} __attribute__ ((packed)); +typedef struct DMCmdLogConfigRsp DMCmdLogConfigRsp; + +/* DIAG_SUBSYS_WCDMA_CALL_START command */ +struct DMCmdSubsysWcdmaCallStart { + DMCmdSubsysHeader hdr; + u_int8_t number_len; + u_int8_t number_digits[32]; + u_int8_t amr_rate; /* default to 7 */ +} __attribute__ ((packed)); +typedef struct DMCmdSubsysWcdmaCallStart DMCmdSubsysWcdmaCallStart; + +/* DIAG_SUBSYS_WCDMA_STATE_INFO response */ +struct DMCmdSubsysWcdmaStateInfoRsp { + DMCmdSubsysHeader hdr; + u_int8_t imei_len; + u_int8_t imei[8]; + u_int8_t imsi_len; + u_int8_t imsi[8]; + u_int8_t l1_state; +} __attribute__ ((packed)); +typedef struct DMCmdSubsysWcdmaStateInfoRsp DMCmdSubsysWcdmaStateInfoRsp; + +/* DIAG_SUBSYS_GSM_STATE_INFO response */ +struct DMCmdSubsysGsmStateInfoRsp { + DMCmdSubsysHeader hdr; + u_int8_t imei_len; + u_int8_t imei[8]; + u_int8_t imsi_len; + u_int8_t imsi[8]; + u_int8_t lai[5]; + u_int16_t cellid; + u_int8_t cm_call_state; + u_int8_t cm_opmode; + u_int8_t cm_sysmode; +} __attribute__ ((packed)); +typedef struct DMCmdSubsysGsmStateInfoRsp DMCmdSubsysGsmStateInfoRsp; + #endif /* LIBQCDM_DM_COMMANDS_H */ diff --git a/libqcdm/src/error.c b/libqcdm/src/error.c deleted file mode 100644 index 994608e..0000000 --- a/libqcdm/src/error.c +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation - * - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "error.h" - -#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -GQuark -qcdm_serial_error_quark (void) -{ - static GQuark ret = 0; - - if (ret == 0) - ret = g_quark_from_static_string ("qcdm-serial-error"); - - return ret; -} - -GType -qcdm_serial_error_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - ENUM_ENTRY (QCDM_SERIAL_CONFIG_FAILED, "SerialConfigFailed"), - { 0, 0, 0 } - }; - - etype = g_enum_register_static ("QcdmSerialError", values); - } - - return etype; -} - -/***************************************************************/ - -GQuark -qcdm_command_error_quark (void) -{ - static GQuark ret = 0; - - if (ret == 0) - ret = g_quark_from_static_string ("qcdm-command-error"); - - return ret; -} - -GType -qcdm_command_error_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - ENUM_ENTRY (QCDM_COMMAND_MALFORMED_RESPONSE, "QcdmCommandMalformedResponse"), - ENUM_ENTRY (QCDM_COMMAND_UNEXPECTED, "QcdmCommandUnexpected"), - ENUM_ENTRY (QCDM_COMMAND_BAD_LENGTH, "QcdmCommandBadLength"), - ENUM_ENTRY (QCDM_COMMAND_BAD_COMMAND, "QcdmCommandBadCommand"), - ENUM_ENTRY (QCDM_COMMAND_BAD_PARAMETER, "QcdmCommandBadParameter"), - ENUM_ENTRY (QCDM_COMMAND_NOT_ACCEPTED, "QcdmCommandNotAccepted"), - ENUM_ENTRY (QCDM_COMMAND_BAD_MODE, "QcdmCommandBadMode"), - ENUM_ENTRY (QCDM_COMMAND_NVCMD_FAILED, "QcdmCommandNvCmdFailed"), - ENUM_ENTRY (QCDM_COMMAND_SPC_LOCKED, "QcdmCommandSpcLocked"), - { 0, 0, 0 } - }; - - etype = g_enum_register_static ("QcdmCommandError", values); - } - - return etype; -} - - diff --git a/libqcdm/src/error.h b/libqcdm/src/error.h deleted file mode 100644 index f0b0534..0000000 --- a/libqcdm/src/error.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation - * - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LIBQCDM_ERROR_H -#define LIBQCDM_ERROR_H - -#include -#include - -enum { - QCDM_SERIAL_CONFIG_FAILED = 0, -}; - -#define QCDM_SERIAL_ERROR (qcdm_serial_error_quark ()) -#define QCDM_TYPE_SERIAL_ERROR (qcdm_serial_error_get_type ()) - -GQuark qcdm_serial_error_quark (void); -GType qcdm_serial_error_get_type (void); - - -enum { - QCDM_COMMAND_MALFORMED_RESPONSE = 0, - QCDM_COMMAND_UNEXPECTED = 1, - QCDM_COMMAND_BAD_LENGTH = 2, - QCDM_COMMAND_BAD_COMMAND = 3, - QCDM_COMMAND_BAD_PARAMETER = 4, - QCDM_COMMAND_NOT_ACCEPTED = 5, - QCDM_COMMAND_BAD_MODE = 6, - QCDM_COMMAND_NVCMD_FAILED = 7, - QCDM_COMMAND_SPC_LOCKED = 8, -}; - -#define QCDM_COMMAND_ERROR (qcdm_command_error_quark ()) -#define QCDM_TYPE_COMMAND_ERROR (qcdm_command_error_get_type ()) - -GQuark qcdm_command_error_quark (void); -GType qcdm_command_error_get_type (void); - -#endif /* LIBQCDM_ERROR_H */ - diff --git a/libqcdm/src/errors.c b/libqcdm/src/errors.c new file mode 100644 index 0000000..12b8d55 --- /dev/null +++ b/libqcdm/src/errors.c @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "errors.h" +#include +#include + +void +_qcdm_log (const char *file, + int line, + const char *func, + int level, + int domain, + const char *format, + ...) +{ + va_list args; + char *message = NULL; + int n; + const char *prefix = "info"; + + qcdm_return_if_fail (format != NULL); + qcdm_return_if_fail (format[0] != '\0'); + + /* level & domain ignored for now */ + + if (getenv ("QCDM_DEBUG") == NULL) + return; + + va_start (args, format); + n = vasprintf (&message, format, args); + va_end (args); + + if (level & QCDM_LOGL_ERR) + prefix = "err"; + else if (level & QCDM_LOGL_WARN) + prefix = "warn"; + else if (level & QCDM_LOGL_DEBUG) + prefix = "dbg"; + + if (n >= 0) { + fprintf (stderr, "<%s> [%s:%u] %s(): %s\n", prefix, file, line, func, message); + free (message); + } +} + diff --git a/libqcdm/src/errors.h b/libqcdm/src/errors.h new file mode 100644 index 0000000..a5507bb --- /dev/null +++ b/libqcdm/src/errors.h @@ -0,0 +1,102 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBQCDM_ERROR_H +#define LIBQCDM_ERROR_H + +#include +#include +#include +#include +#include + +enum { + QCDM_LOGL_ERR = 0x00000001, + QCDM_LOGL_WARN = 0x00000002, + QCDM_LOGL_INFO = 0x00000004, + QCDM_LOGL_DEBUG = 0x00000008 +}; + +enum { + QCDM_SUCCESS = 0, + QCDM_ERROR_INVALID_ARGUMENTS = 1, + QCDM_ERROR_SERIAL_CONFIG_FAILED = 2, + QCDM_ERROR_VALUE_NOT_FOUND = 3, + QCDM_ERROR_RESPONSE_UNEXPECTED = 4, + QCDM_ERROR_RESPONSE_BAD_LENGTH = 5, + QCDM_ERROR_RESPONSE_MALFORMED = 6, + QCDM_ERROR_RESPONSE_BAD_COMMAND = 7, + QCDM_ERROR_RESPONSE_BAD_PARAMETER = 8, + QCDM_ERROR_RESPONSE_NOT_ACCEPTED = 9, + QCDM_ERROR_RESPONSE_BAD_MODE = 10, + QCDM_ERROR_NVCMD_FAILED = 11, + QCDM_ERROR_SPC_LOCKED = 12, + QCDM_ERROR_NV_ERROR_BUSY = 13, + QCDM_ERROR_NV_ERROR_BAD_COMMAND = 14, + QCDM_ERROR_NV_ERROR_MEMORY_FULL = 15, + QCDM_ERROR_NV_ERROR_FAILED = 16, + QCDM_ERROR_NV_ERROR_INACTIVE = 17, /* NV location is not active */ + QCDM_ERROR_NV_ERROR_BAD_PARAMETER = 18, + QCDM_ERROR_NV_ERROR_READ_ONLY = 19, /* NV location is read-only */ + QCDM_ERROR_RESPONSE_FAILED = 20, /* command-specific failure */ +}; + +#define qcdm_assert assert +#define qcdm_assert_not_reached() assert(0) + +#define qcdm_return_if_fail(e) \ +{ \ + if (!(e)) { \ + qcdm_warn (0, "failed: " #e "\n"); \ + return; \ + } \ +} + +#define qcdm_return_val_if_fail(e, v) \ +{ \ + if (!(e)) { \ + qcdm_warn (0, "failed: " #e "\n"); \ + return v; \ + } \ +} + +#define qcdm_warn_if_fail(e) \ +{ \ + if (!(e)) { \ + qcdm_warn (0, "failed: " #e "\n"); \ + } \ +} + +void _qcdm_log (const char *file, + int line, + const char *func, + int domain, + int level, + const char *format, + ...) __attribute__((__format__ (__printf__, 6, 7))); + +#define qcdm_dbg(domain, ...) \ + _qcdm_log (__FILE__, __LINE__, __func__, domain, QCDM_LOGL_DEBUG, ## __VA_ARGS__ ) + +#define qcdm_warn(domain, ...) \ + _qcdm_log (__FILE__, __LINE__, __func__, domain, QCDM_LOGL_WARN, ## __VA_ARGS__ ) + +#define qcdm_err(domain, ...) \ + _qcdm_log (__FILE__, __LINE__, __func__, domain, QCDM_LOGL_ERR, ## __VA_ARGS__ ) + +#endif /* LIBQCDM_ERROR_H */ + diff --git a/libqcdm/src/log-items.h b/libqcdm/src/log-items.h new file mode 100644 index 0000000..5b44fcd --- /dev/null +++ b/libqcdm/src/log-items.h @@ -0,0 +1,161 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBQCDM_LOG_ITEMS_H +#define LIBQCDM_LOG_ITEMS_H + +enum { + /* CDMA and EVDO items */ + DM_LOG_ITEM_CDMA_ACCESS_CHANNEL_MSG = 0x1004, + DM_LOG_ITEM_CDMA_REV_CHANNEL_TRAFFIC_MSG = 0x1005, + DM_LOG_ITEM_CDMA_SYNC_CHANNEL_MSG = 0x1006, + DM_LOG_ITEM_CDMA_PAGING_CHANNEL_MSG = 0x1007, + DM_LOG_ITEM_CDMA_FWD_CHANNEL_TRAFFIC_MSG = 0x1008, + DM_LOG_ITEM_CDMA_FWD_LINK_VOCODER_PACKET = 0x1009, + DM_LOG_ITEM_CDMA_REV_LINK_VOCODER_PACKET = 0x100A, + DM_LOG_ITEM_CDMA_MARKOV_STATS = 0x100E, + DM_LOG_ITEM_EVDO_HANDOFF_STATE = 0x105E, + DM_LOG_ITEM_EVDO_ACTIVE_PILOT_SET = 0x105F, + DM_LOG_ITEM_EVDO_REV_LINK_PACKET_SUMMARY = 0x1060, + DM_LOG_ITEM_EVDO_REV_TRAFFIC_RATE_COUNT = 0x1062, + DM_LOG_ITEM_EVDO_REV_POWER_CONTROL = 0x1063, + DM_LOG_ITEM_EVDO_ARQ_EFFECTIVE_RECEIVE_RATE = 0x1066, + DM_LOG_ITEM_EVDO_AIR_LINK_SUMMARY = 0x1068, + DM_LOG_ITEM_EVDO_POWER = 0x1069 + DM_LOG_ITEM_EVDO_FWD_LINK_PACKET_SNAPSHOT = 0x106A, + DM_LOG_ITEM_EVDO_ACCESS_ATTEMPT = 0x106C, + DM_LOG_ITEM_EVDO_REV_ACTIVITY_BITS_BUFFER = 0x106D, + DM_LOG_ITEM_CDMA_REVERSE_POWER_CONTROL = 0x102c, + DM_LOG_ITEM_CDMA_SERVICE_CONFIG = 0x102e, + + /* WCDMA items */ + DM_LOG_ITEM_WCDMA_AGC_INFO = 0x4105, + DM_LOG_ITEM_WCDMA_RRC_STATE = 0x4125, + + /* GSM items */ + DM_LOG_ITEM_GSM_BURST_METRICS = 0x506c, + DM_LOG_ITEM_GSM_BCCH_MESSAGE = 0x5134, +}; + + +/* DM_LOG_ITEM_CDMA_PAGING_CHANNEL_MSG */ +struct DMLogItemPagingChannelMsg { + u_int8_t msg_len; /* size of entire struct including this field */ + u_int8_t msg_type; /* MSG_TYPE as in 3GPP2 C.S0004 Table 3.1.2.3.1.1.2 */ + u_int8_t data[0]; /* Packed message as in 3GPP2 C.S0005 3.7.2.3.2.x */ +} __attribute ((packed)); +typedef struct DMLogItemPagingChannelMsg DMLogItemPagingChannelMsg; + + +/* DM_LOG_ITEM_CDMA_REVERSE_POWER_CONTROL */ +struct DMLogItemRPCItem { + u_int8_t channel_set_mask; + u_int16_t frame_count; + u_int8_t len_per_frame; + u_int16_t dec_history; + u_int8_t rx_agc_vals; + u_int8_t tx_power_vals; + u_int8_t tx_gain_adjust; +} __attribute__ ((packed)); +typedef struct DMLogItemRPCItem DMLogItemRPCItem; + +struct DMLogItemCdmaReversePowerControl { + u_int8_t frame_offset; + u_int8_t band_class; + u_int16_t rev_chan_rc; + u_int8_t pilot_gating_rate; + u_int8_t step_size; + u_int8_t num_records; + DMLogItemRPCItem records[]; +} __attribute__ ((packed)); +typedef struct DMLogItemCdmaReversePowerControl DMLogItemCdmaReversePowerControl; + + +/* DM_LOG_ITEM_WCDMA_AGC_INFO */ +struct DMLogItemWcdmRrcState { + u_int8_t num_samples; + u_int16_t rx_agc; + u_int16_t tx_agc; + u_int16_t rx_agc_adj_pdm; + u_int16_t tx_agc_adj_pdm; + u_int16_t max_tx; + /* Bit 4 means tx_agc is valid */ + u_int8_t agc_info; +} __attribute__ ((packed)); +typedef struct DMLogItemWcdmRrcState DMLogItemWcdmRrcState; + + +/* DM_LOG_ITEM_WCDMA_RRC_STATE */ +enum { + DM_LOG_ITEM_WCDMA_RRC_STATE_DISCONNECTED = 0, + DM_LOG_ITEM_WCDMA_RRC_STATE_CONNECTING = 1, + DM_LOG_ITEM_WCDMA_RRC_STATE_CELL_FACH = 2, + DM_LOG_ITEM_WCDMA_RRC_STATE_CELL_DCH = 3, + DM_LOG_ITEM_WCDMA_RRC_STATE_CELL_PCH = 4, + DM_LOG_ITEM_WCDMA_RRC_STATE_URA_PCH = 5, +}; + +struct DMLogItemWcdmRrcState { + u_int8_t rrc_state; +} __attribute__ ((packed)); +typedef struct DMLogItemWcdmRrcState DMLogItemWcdmRrcState; + + +/* DM_LOG_ITEM_GSM_BURST_METRICS */ +struct DMLogItemGsmBurstMetric { + u_int32_t fn; + u_int16_t arfcn; + u_int32_t rssi; + u_int16_t power; + u_int16_t dc_offset_i; + u_int16_t dc_offset_q; + u_int16_t freq_offset; + u_int16_t timing_offset; + u_int16_t snr; + u_int8_t gain_state; +} __attribute__ ((packed)); +typedef struct DMLogItemGsmBurstMetric DMLogItemGsmBurstMetric; + +struct DMLogItemGsmBurstMetrics { + u_int8_t channel; + DMLogItemBurstMetric metrics[4]; +} __attribute__ ((packed)); +typedef struct DMLogItemGsmBurstMetrics DMLogItemGsmBurstMetrics; + + +/* DM_LOG_ITEM_GSM_BCCH_MESSAGE */ +enum { + DM_LOG_ITEM_GSM_BCCH_BAND_UNKNOWN = 0, + DM_LOG_ITEM_GSM_BCCH_BAND_GSM_900 = 8, + DM_LOG_ITEM_GSM_BCCH_BAND_DCS_1800 = 9, + DM_LOG_ITEM_GSM_BCCH_BAND_PCS_1900 = 10, + DM_LOG_ITEM_GSM_BCCH_BAND_GSM_850 = 11, + DM_LOG_ITEM_GSM_BCCH_BAND_GSM_450 = 12, +}; + +struct DMLogItemGsmBcchMessage { + /* Band is top 4 bits; lower 12 is ARFCN */ + u_int16_t bcch_arfcn; + u_int16_t bsic; + u_int16_t cell_id; + u_int8_t lai[5]; + u_int8_t cell_selection_prio; + u_int8_t ncc_permitted; +} __attribute__ ((packed)); +typedef struct DMLogItemGsmBcchMessage DMLogItemGsmBcchMessage; + +#endif /* LIBQCDM_LOG_ITEMS_H */ diff --git a/libqcdm/src/nv-items.h b/libqcdm/src/nv-items.h index 8240866..eca9d65 100644 --- a/libqcdm/src/nv-items.h +++ b/libqcdm/src/nv-items.h @@ -18,6 +18,20 @@ #ifndef LIBQCDM_NV_ITEMS_H #define LIBQCDM_NV_ITEMS_H +#include + +/* NV read/write status codes */ +typedef enum { + DIAG_NV_STATUS_OK = 0, + DIAG_NV_STATUS_BUSY = 1, + DIAG_NV_STATUS_BAD_COMMAND = 2, + DIAG_NV_STATUS_MEMORY_FULL = 3, + DIAG_NV_STATUS_FAILED = 4, + DIAG_NV_STATUS_INACTIVE = 5, /* NV location not active */ + DIAG_NV_STATUS_BAD_PARAMETER = 6, + DIAG_NV_STATUS_READ_ONLY = 7, /* NV location is read-only */ +} DMNVStatus; + enum { DIAG_NV_MODE_PREF = 10, /* Mode preference: 1x, HDR, auto */ DIAG_NV_DIR_NUMBER = 178, /* Mobile Directory Number (MDN) */ @@ -28,7 +42,13 @@ enum { /* Mode preference values */ enum { + DIAG_NV_MODE_PREF_DIGITAL = 0x00, + DIAG_NV_MODE_PREF_DIGITAL_ONLY = 0x01, + DIAG_NV_MODE_PREF_ANALOG = 0x02, + DIAG_NV_MODE_PREF_ANALOG_ONLY = 0x03, DIAG_NV_MODE_PREF_AUTO = 0x04, + DIAG_NV_MODE_PREF_E911 = 0x05, + DIAG_NV_MODE_PREF_HOME_ONLY = 0x06, DIAG_NV_MODE_PREF_1X_ONLY = 0x09, DIAG_NV_MODE_PREF_HDR_ONLY = 0x0A, DIAG_NV_MODE_PREF_1X_HDR_ONLY = 0x0D, @@ -38,15 +58,15 @@ enum { /* DIAG_NV_MODE_PREF */ struct DMNVItemModePref { - guint8 profile; - guint8 mode_pref; + u_int8_t profile; + u_int8_t mode_pref; } __attribute__ ((packed)); typedef struct DMNVItemModePref DMNVItemModePref; /* DIAG_NV_DIR_NUMBER */ struct DMNVItemMdn { - guint8 profile; - guint8 mdn[10]; + u_int8_t profile; + u_int8_t mdn[10]; } __attribute__ ((packed)); typedef struct DMNVItemMdn DMNVItemMdn; @@ -59,8 +79,8 @@ enum { /* DIAG_NV_ROAM_PREF */ struct DMNVItemRoamPref { - guint8 profile; - guint8 roam_pref; + u_int8_t profile; + u_int8_t roam_pref; } __attribute__ ((packed)); typedef struct DMNVItemRoamPref DMNVItemRoamPref; @@ -73,7 +93,7 @@ enum { /* DIAG_NV_HDR_REV_PREF */ struct DMNVItemHdrRevPref { - guint8 rev_pref; + u_int8_t rev_pref; } __attribute__ ((packed)); typedef struct DMNVItemHdrRevPref DMNVItemHdrRevPref; diff --git a/libqcdm/src/result-private.h b/libqcdm/src/result-private.h index 0db63f5..382411c 100644 --- a/libqcdm/src/result-private.h +++ b/libqcdm/src/result-private.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* - * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2011 Red Hat, Inc. * * This program is free software: you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -18,34 +18,36 @@ #ifndef LIBQCDM_RESULT_PRIVATE_H #define LIBQCDM_RESULT_PRIVATE_H -#include -#include #include "result.h" -QCDMResult *qcdm_result_new (void); +QcdmResult *qcdm_result_new (void); -/* For these functions, 'key' *must* be a constant, not allocated and freed */ - -void qcdm_result_add_string (QCDMResult *result, +void qcdm_result_add_string (QcdmResult *result, const char *key, const char *str); -void qcdm_result_add_uint8 (QCDMResult *result, +void qcdm_result_add_u8 (QcdmResult *result, const char *key, - guint8 num); + u_int8_t num); -void qcdm_result_add_uint32 (QCDMResult *result, - const char *key, - guint32 num); +void qcdm_result_add_u8_array (QcdmResult *result, + const char *key, + const u_int8_t *array, + size_t array_len); -void qcdm_result_add_boxed (QCDMResult *result, - const char *key, - GType btype, - gpointer boxed); +int qcdm_result_get_u8_array (QcdmResult *result, + const char *key, + const u_int8_t **out_val, + size_t *out_len); -gboolean qcdm_result_get_boxed (QCDMResult *result, +void qcdm_result_add_u16_array (QcdmResult *result, const char *key, - gpointer *out_val); + const u_int16_t *array, + size_t array_len); + +void qcdm_result_add_u32 (QcdmResult *result, + const char *key, + u_int32_t num); #endif /* LIBQCDM_RESULT_PRIVATE_H */ diff --git a/libqcdm/src/result.c b/libqcdm/src/result.c index 2440478..d51a050 100644 --- a/libqcdm/src/result.c +++ b/libqcdm/src/result.c @@ -16,233 +16,436 @@ */ #include -#include +#include #include "result.h" #include "result-private.h" -#include "error.h" - -struct QCDMResult { - guint32 refcount; - GHashTable *hash; +#include "errors.h" + +/*********************************************************/ + +typedef struct Val Val; + +typedef enum { + VAL_TYPE_NONE = 0, + VAL_TYPE_STRING = 1, + VAL_TYPE_U8 = 2, + VAL_TYPE_U32 = 3, + VAL_TYPE_U8_ARRAY = 4, + VAL_TYPE_U16_ARRAY = 5, +} ValType; + +struct Val { + char *key; + u_int8_t type; + union { + char *s; + u_int8_t u8; + u_int32_t u32; + u_int8_t *u8_array; + u_int16_t *u16_array; + } u; + u_int32_t array_len; + Val *next; }; - static void -gvalue_destroy (gpointer data) +val_free (Val *v) { - GValue *value = (GValue *) data; + if (v->type == VAL_TYPE_STRING) { + if (v->u.s) + free (v->u.s); + } else if (v->type == VAL_TYPE_U8_ARRAY) { + if (v->u.u8_array); + free (v->u.u8_array); + } else if (v->type == VAL_TYPE_U16_ARRAY) { + if (v->u.u16_array); + free (v->u.u16_array); + } + free (v->key); + memset (v, 0, sizeof (*v)); + free (v); +} + +static Val * +val_new_string (const char *key, const char *value) +{ + Val *v; + + qcdm_return_val_if_fail (key != NULL, NULL); + qcdm_return_val_if_fail (key[0] != '\0', NULL); + qcdm_return_val_if_fail (value != NULL, NULL); - g_value_unset (value); - g_slice_free (GValue, value); + v = calloc (sizeof (Val), 1); + if (v == NULL) + return NULL; + + v->key = strdup (key); + v->type = VAL_TYPE_STRING; + v->u.s = strdup (value); + return v; } -QCDMResult * -qcdm_result_new (void) +static Val * +val_new_u8 (const char *key, u_int8_t u) { - QCDMResult *result; + Val *v; - g_type_init (); + qcdm_return_val_if_fail (key != NULL, NULL); + qcdm_return_val_if_fail (key[0] != '\0', NULL); - result = g_malloc0 (sizeof (QCDMResult)); - result->hash = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, gvalue_destroy); - result->refcount = 1; - return result; + v = calloc (sizeof (Val), 1); + if (v == NULL) + return NULL; + + v->key = strdup (key); + v->type = VAL_TYPE_U8; + v->u.u8 = u; + return v; } -QCDMResult * -qcdm_result_ref (QCDMResult *result) +static Val * +val_new_u8_array (const char *key, const u_int8_t *array, size_t array_len) { - g_return_val_if_fail (result != NULL, NULL); - g_return_val_if_fail (result->refcount > 0, NULL); + Val *v; + + qcdm_return_val_if_fail (key != NULL, NULL); + qcdm_return_val_if_fail (key[0] != '\0', NULL); + qcdm_return_val_if_fail (array != NULL, NULL); + qcdm_return_val_if_fail (array_len > 0, NULL); + + v = calloc (sizeof (Val), 1); + if (v == NULL) + return NULL; + + v->key = strdup (key); + v->type = VAL_TYPE_U8_ARRAY; + v->u.u8_array = malloc (array_len); + if (v->u.u8_array == NULL) { + val_free (v); + return NULL; + } + memcpy (v->u.u8_array, array, array_len); + v->array_len = array_len; - result->refcount++; - return result; + return v; } -void -qcdm_result_unref (QCDMResult *result) +static Val * +val_new_u32 (const char *key, u_int32_t u) { - g_return_if_fail (result != NULL); - g_return_if_fail (result->refcount > 0); + Val *v; + + qcdm_return_val_if_fail (key != NULL, NULL); + qcdm_return_val_if_fail (key[0] != '\0', NULL); + + v = calloc (sizeof (Val), 1); + if (v == NULL) + return NULL; - result->refcount--; - if (result->refcount == 0) { - g_hash_table_destroy (result->hash); - memset (result, 0, sizeof (QCDMResult)); - g_free (result); + v->key = strdup (key); + v->type = VAL_TYPE_U32; + v->u.u32 = u; + return v; +} + +static Val * +val_new_u16_array (const char *key, const u_int16_t *array, size_t array_len) +{ + Val *v; + size_t sz; + + qcdm_return_val_if_fail (key != NULL, NULL); + qcdm_return_val_if_fail (key[0] != '\0', NULL); + qcdm_return_val_if_fail (array != NULL, NULL); + qcdm_return_val_if_fail (array_len > 0, NULL); + + v = calloc (sizeof (Val), 1); + if (v == NULL) + return NULL; + + v->key = strdup (key); + v->type = VAL_TYPE_U16_ARRAY; + sz = sizeof (u_int16_t) * array_len; + v->u.u16_array = malloc (sz); + if (v->u.u16_array == NULL) { + val_free (v); + return NULL; } + memcpy (v->u.u16_array, array, sz); + v->array_len = array_len; + + return v; } -void -qcdm_result_add_string (QCDMResult *result, - const char *key, - const char *str) +/*********************************************************/ + +struct QcdmResult { + u_int32_t refcount; + Val *first; +}; + +QcdmResult * +qcdm_result_new (void) { - GValue *val; + QcdmResult *r; - g_return_if_fail (result != NULL); - g_return_if_fail (result->refcount > 0); - g_return_if_fail (key != NULL); - g_return_if_fail (str != NULL); + r = calloc (sizeof (QcdmResult), 1); + if (r) + r->refcount = 1; + return r; +} - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, str); +QcdmResult * +qcdm_result_ref (QcdmResult *r) +{ + qcdm_return_val_if_fail (r != NULL, NULL); + qcdm_return_val_if_fail (r->refcount > 0, NULL); - g_hash_table_insert (result->hash, (gpointer) key, val); + r->refcount++; + return r; } -gboolean -qcdm_result_get_string (QCDMResult *result, - const char *key, - const char **out_val) +static void +qcdm_result_free (QcdmResult *r) { - GValue *val; + Val *v, *n; - g_return_val_if_fail (result != NULL, FALSE); - g_return_val_if_fail (result->refcount > 0, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (out_val != NULL, FALSE); - g_return_val_if_fail (*out_val == NULL, FALSE); + v = r->first; + while (v) { + n = v->next; + val_free (v); + v = n; + } + memset (r, 0, sizeof (*r)); + free (r); +} - val = g_hash_table_lookup (result->hash, key); - if (!val) - return FALSE; +void +qcdm_result_unref (QcdmResult *r) +{ + qcdm_return_if_fail (r != NULL); + qcdm_return_if_fail (r->refcount > 0); - g_warn_if_fail (G_VALUE_HOLDS_STRING (val)); - if (!G_VALUE_HOLDS_STRING (val)) - return FALSE; + r->refcount--; + if (r->refcount == 0) + qcdm_result_free (r); +} - *out_val = g_value_get_string (val); - return TRUE; +static Val * +find_val (QcdmResult *r, const char *key, ValType expected_type) +{ + Val *v, *n; + + v = r->first; + while (v) { + n = v->next; + if (strcmp (v->key, key) == 0) { + /* Check type */ + qcdm_return_val_if_fail (v->type == expected_type, NULL); + return v; + } + v = n; + } + return NULL; } void -qcdm_result_add_uint8 (QCDMResult *result, - const char *key, - guint8 num) +qcdm_result_add_string (QcdmResult *r, + const char *key, + const char *str) { - GValue *val; - - g_return_if_fail (result != NULL); - g_return_if_fail (result->refcount > 0); - g_return_if_fail (key != NULL); + Val *v; - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UCHAR); - g_value_set_uchar (val, (unsigned char) num); + qcdm_return_if_fail (r != NULL); + qcdm_return_if_fail (r->refcount > 0); + qcdm_return_if_fail (key != NULL); + qcdm_return_if_fail (str != NULL); - g_hash_table_insert (result->hash, (gpointer) key, val); + v = val_new_string (key, str); + qcdm_return_if_fail (v != NULL); + v->next = r->first; + r->first = v; } -gboolean -qcdm_result_get_uint8 (QCDMResult *result, - const char *key, - guint8 *out_val) +int +qcdm_result_get_string (QcdmResult *r, + const char *key, + const char **out_val) { - GValue *val; - - g_return_val_if_fail (result != NULL, FALSE); - g_return_val_if_fail (result->refcount > 0, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (out_val != NULL, FALSE); + Val *v; - val = g_hash_table_lookup (result->hash, key); - if (!val) - return FALSE; + qcdm_return_val_if_fail (r != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (r->refcount > 0, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (key != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (out_val != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (*out_val == NULL, -QCDM_ERROR_INVALID_ARGUMENTS); - g_warn_if_fail (G_VALUE_HOLDS_UCHAR (val)); - if (!G_VALUE_HOLDS_UCHAR (val)) - return FALSE; + v = find_val (r, key, VAL_TYPE_STRING); + if (v == NULL) + return -QCDM_ERROR_VALUE_NOT_FOUND; - *out_val = (guint8) g_value_get_uchar (val); - return TRUE; + *out_val = v->u.s; + return 0; } void -qcdm_result_add_uint32 (QCDMResult *result, - const char *key, - guint32 num) +qcdm_result_add_u8 (QcdmResult *r, + const char *key, + u_int8_t num) +{ + Val *v; + + qcdm_return_if_fail (r != NULL); + qcdm_return_if_fail (r->refcount > 0); + qcdm_return_if_fail (key != NULL); + + v = val_new_u8 (key, num); + qcdm_return_if_fail (v != NULL); + v->next = r->first; + r->first = v; +} + +int +qcdm_result_get_u8 (QcdmResult *r, + const char *key, + u_int8_t *out_val) { - GValue *val; + Val *v; - g_return_if_fail (result != NULL); - g_return_if_fail (result->refcount > 0); - g_return_if_fail (key != NULL); + qcdm_return_val_if_fail (r != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (r->refcount > 0, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (key != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (out_val != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UINT); - g_value_set_uint (val, num); + v = find_val (r, key, VAL_TYPE_U8); + if (v == NULL) + return -QCDM_ERROR_VALUE_NOT_FOUND; - g_hash_table_insert (result->hash, (gpointer) key, val); + *out_val = v->u.u8; + return 0; } -gboolean -qcdm_result_get_uint32 (QCDMResult *result, - const char *key, - guint32 *out_val) +void +qcdm_result_add_u8_array (QcdmResult *r, + const char *key, + const u_int8_t *array, + size_t array_len) { - GValue *val; + Val *v; + + qcdm_return_if_fail (r != NULL); + qcdm_return_if_fail (r->refcount > 0); + qcdm_return_if_fail (key != NULL); + qcdm_return_if_fail (array != NULL); + qcdm_return_if_fail (array_len >= 0); + + v = val_new_u8_array (key, array, array_len); + qcdm_return_if_fail (v != NULL); + v->next = r->first; + r->first = v; +} - g_return_val_if_fail (result != NULL, FALSE); - g_return_val_if_fail (result->refcount > 0, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (out_val != NULL, FALSE); +int +qcdm_result_get_u8_array (QcdmResult *r, + const char *key, + const u_int8_t **out_val, + size_t *out_len) +{ + Val *v; - val = g_hash_table_lookup (result->hash, key); - if (!val) - return FALSE; + qcdm_return_val_if_fail (r != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (r->refcount > 0, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (key != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (out_val != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (out_len != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); - g_warn_if_fail (G_VALUE_HOLDS_UINT (val)); - if (!G_VALUE_HOLDS_UINT (val)) - return FALSE; + v = find_val (r, key, VAL_TYPE_U8_ARRAY); + if (v == NULL) + return -QCDM_ERROR_VALUE_NOT_FOUND; - *out_val = (guint32) g_value_get_uint (val); - return TRUE; + *out_val = v->u.u8_array; + *out_len = v->array_len; + return 0; } void -qcdm_result_add_boxed (QCDMResult *result, - const char *key, - GType btype, - gpointer boxed) +qcdm_result_add_u32 (QcdmResult *r, + const char *key, + u_int32_t num) { - GValue *val; + Val *v; - g_return_if_fail (result != NULL); - g_return_if_fail (result->refcount > 0); - g_return_if_fail (key != NULL); + qcdm_return_if_fail (r != NULL); + qcdm_return_if_fail (r->refcount > 0); + qcdm_return_if_fail (key != NULL); - val = g_slice_new0 (GValue); - g_value_init (val, btype); - g_value_set_static_boxed (val, boxed); + v = val_new_u32 (key, num); + qcdm_return_if_fail (v != NULL); + v->next = r->first; + r->first = v; +} + +int +qcdm_result_get_u32 (QcdmResult *r, + const char *key, + u_int32_t *out_val) +{ + Val *v; - g_hash_table_insert (result->hash, (gpointer) key, val); + qcdm_return_val_if_fail (r != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (r->refcount > 0, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (key != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (out_val != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + + v = find_val (r, key, VAL_TYPE_U32); + if (v == NULL) + return -QCDM_ERROR_VALUE_NOT_FOUND; + + *out_val = v->u.u32; + return 0; } -gboolean -qcdm_result_get_boxed (QCDMResult *result, - const char *key, - gpointer *out_val) +void +qcdm_result_add_u16_array (QcdmResult *r, + const char *key, + const u_int16_t *array, + size_t array_len) { - GValue *val; + Val *v; + + qcdm_return_if_fail (r != NULL); + qcdm_return_if_fail (r->refcount > 0); + qcdm_return_if_fail (key != NULL); + qcdm_return_if_fail (array != NULL); + qcdm_return_if_fail (array_len >= 0); + + v = val_new_u16_array (key, array, array_len); + qcdm_return_if_fail (v != NULL); + v->next = r->first; + r->first = v; +} - g_return_val_if_fail (result != NULL, FALSE); - g_return_val_if_fail (result->refcount > 0, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (out_val != NULL, FALSE); +int +qcdm_result_get_u16_array (QcdmResult *r, + const char *key, + const u_int16_t **out_val, + size_t *out_len) +{ + Val *v; - val = g_hash_table_lookup (result->hash, key); - if (!val) - return FALSE; + qcdm_return_val_if_fail (r != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (r->refcount > 0, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (key != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (out_val != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); + qcdm_return_val_if_fail (out_len != NULL, -QCDM_ERROR_INVALID_ARGUMENTS); - g_warn_if_fail (G_VALUE_HOLDS_BOXED (val)); - if (!G_VALUE_HOLDS_BOXED (val)) - return FALSE; + v = find_val (r, key, VAL_TYPE_U16_ARRAY); + if (v == NULL) + return -QCDM_ERROR_VALUE_NOT_FOUND; - *out_val = g_value_get_boxed (val); - return TRUE; + *out_val = v->u.u16_array; + *out_len = v->array_len; + return 0; } diff --git a/libqcdm/src/result.h b/libqcdm/src/result.h index 4912b07..a71c0bf 100644 --- a/libqcdm/src/result.h +++ b/libqcdm/src/result.h @@ -18,25 +18,30 @@ #ifndef LIBQCDM_RESULT_H #define LIBQCDM_RESULT_H -#include +#include -typedef struct QCDMResult QCDMResult; +typedef struct QcdmResult QcdmResult; -gboolean qcdm_result_get_string (QCDMResult *result, - const char *key, - const char **out_val); +int qcdm_result_get_string (QcdmResult *r, + const char *key, + const char **out_val); -gboolean qcdm_result_get_uint8 (QCDMResult *result, - const char *key, - guint8 *out_val); +int qcdm_result_get_u8 (QcdmResult *r, + const char *key, + u_int8_t *out_val); -gboolean qcdm_result_get_uint32 (QCDMResult *result, - const char *key, - guint32 *out_val); +int qcdm_result_get_u32 (QcdmResult *r, + const char *key, + u_int32_t *out_val); -QCDMResult *qcdm_result_ref (QCDMResult *result); +int qcdm_result_get_u16_array (QcdmResult *result, + const char *key, + const u_int16_t **out_val, + size_t *out_len); -void qcdm_result_unref (QCDMResult *result); +QcdmResult *qcdm_result_ref (QcdmResult *r); + +void qcdm_result_unref (QcdmResult *r); #endif /* LIBQCDM_RESULT_H */ diff --git a/libqcdm/src/utils.c b/libqcdm/src/utils.c index b581548..922d1cb 100644 --- a/libqcdm/src/utils.c +++ b/libqcdm/src/utils.c @@ -23,6 +23,7 @@ #include #include "utils.h" +#include "errors.h" /* QCDM protocol frames are pseudo Async HDLC frames which end with a 3-byte * trailer. This trailer consists of the 16-bit CRC of the frame plus an ending @@ -32,7 +33,7 @@ */ /* Table of CRCs for each possible byte, with a generator polynomial of 0x8408 */ -const guint16 crc_table[256] = { +const u_int16_t crc_table[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, @@ -68,10 +69,10 @@ const guint16 crc_table[256] = { }; /* Calculate the CRC for a buffer using a seed of 0xffff */ -guint16 -crc16 (const char *buffer, gsize len) +u_int16_t +crc16 (const char *buffer, size_t len) { - guint16 crc = 0xffff; + u_int16_t crc = 0xffff; while (len--) crc = crc_table[(crc ^ *buffer++) & 0xff] ^ (crc >> 8); @@ -84,20 +85,20 @@ crc16 (const char *buffer, gsize len) /* Performs DM escaping on inbuf putting the result into outbuf, and returns * the final length of the buffer. */ -gsize +size_t dm_escape (const char *inbuf, - gsize inbuf_len, + size_t inbuf_len, char *outbuf, - gsize outbuf_len) + size_t outbuf_len) { const char *src = inbuf; char *dst = outbuf; size_t i = inbuf_len; - g_return_val_if_fail (inbuf != NULL, 0); - g_return_val_if_fail (inbuf_len > 0, 0); - g_return_val_if_fail (outbuf != NULL, 0); - g_return_val_if_fail (outbuf_len > inbuf_len, 0); + qcdm_return_val_if_fail (inbuf != NULL, 0); + qcdm_return_val_if_fail (inbuf_len > 0, 0); + qcdm_return_val_if_fail (outbuf != NULL, 0); + qcdm_return_val_if_fail (outbuf_len > inbuf_len, 0); /* Since escaping potentially doubles the # of bytes, short-circuit the * length check if destination buffer is clearly large enough. Note the @@ -136,18 +137,18 @@ dm_escape (const char *inbuf, return (dst - outbuf); } -gsize +size_t dm_unescape (const char *inbuf, - gsize inbuf_len, + size_t inbuf_len, char *outbuf, - gsize outbuf_len, - gboolean *escaping) + size_t outbuf_len, + qcdmbool *escaping) { size_t i, outsize; - g_return_val_if_fail (inbuf_len > 0, 0); - g_return_val_if_fail (outbuf_len >= inbuf_len, 0); - g_return_val_if_fail (escaping != NULL, 0); + qcdm_return_val_if_fail (inbuf_len > 0, 0); + qcdm_return_val_if_fail (outbuf_len >= inbuf_len, 0); + qcdm_return_val_if_fail (escaping != NULL, 0); for (i = 0, outsize = 0; i < inbuf_len; i++) { if (*escaping) { @@ -179,20 +180,20 @@ dm_unescape (const char *inbuf, * * Returns: size of the encapsulated QCDM command writted to @outbuf. **/ -gsize +size_t dm_encapsulate_buffer (char *inbuf, - gsize cmd_len, - gsize inbuf_len, + size_t cmd_len, + size_t inbuf_len, char *outbuf, - gsize outbuf_len) + size_t outbuf_len) { - guint16 crc; - gsize escaped_len; + u_int16_t crc; + size_t escaped_len; - g_return_val_if_fail (inbuf != NULL, 0); - g_return_val_if_fail (cmd_len >= 1, 0); - g_return_val_if_fail (inbuf_len >= cmd_len + 2, 0); /* space for CRC */ - g_return_val_if_fail (outbuf != NULL, 0); + qcdm_return_val_if_fail (inbuf != NULL, 0); + qcdm_return_val_if_fail (cmd_len >= 1, 0); + qcdm_return_val_if_fail (inbuf_len >= cmd_len + 2, 0); /* space for CRC */ + qcdm_return_val_if_fail (outbuf != NULL, 0); /* Add the CRC */ crc = crc16 (inbuf, cmd_len); @@ -200,7 +201,7 @@ dm_encapsulate_buffer (char *inbuf, inbuf[cmd_len++] = (crc >> 8) & 0xFF; escaped_len = dm_escape (inbuf, cmd_len, outbuf, outbuf_len); - g_return_val_if_fail (outbuf_len > escaped_len, 0); + qcdm_return_val_if_fail (outbuf_len > escaped_len, 0); outbuf[escaped_len++] = DIAG_CONTROL_CHAR; return escaped_len; @@ -230,25 +231,25 @@ dm_encapsulate_buffer (char *inbuf, * all cases the caller should advance the buffer by the number of bytes * returned in @out_used before calling this function again. **/ -gboolean +qcdmbool dm_decapsulate_buffer (const char *inbuf, - gsize inbuf_len, + size_t inbuf_len, char *outbuf, - gsize outbuf_len, - gsize *out_decap_len, - gsize *out_used, - gboolean *out_need_more) + size_t outbuf_len, + size_t *out_decap_len, + size_t *out_used, + qcdmbool *out_need_more) { - gboolean escaping = FALSE; - gsize i, pkt_len = 0, unesc_len; - guint16 crc, pkt_crc; - - g_return_val_if_fail (inbuf != NULL, FALSE); - g_return_val_if_fail (outbuf != NULL, FALSE); - g_return_val_if_fail (outbuf_len > 0, FALSE); - g_return_val_if_fail (out_decap_len != NULL, FALSE); - g_return_val_if_fail (out_used != NULL, FALSE); - g_return_val_if_fail (out_need_more != NULL, FALSE); + qcdmbool escaping = FALSE; + size_t i, pkt_len = 0, unesc_len; + u_int16_t crc, pkt_crc; + + qcdm_return_val_if_fail (inbuf != NULL, FALSE); + qcdm_return_val_if_fail (outbuf != NULL, FALSE); + qcdm_return_val_if_fail (outbuf_len > 0, FALSE); + qcdm_return_val_if_fail (out_decap_len != NULL, FALSE); + qcdm_return_val_if_fail (out_used != NULL, FALSE); + qcdm_return_val_if_fail (out_need_more != NULL, FALSE); *out_decap_len = 0; *out_used = 0; diff --git a/libqcdm/src/utils.h b/libqcdm/src/utils.h index 5fccf7f..e8cb0b7 100644 --- a/libqcdm/src/utils.h +++ b/libqcdm/src/utils.h @@ -18,37 +18,46 @@ #ifndef UTILS_H #define UTILS_H -#include +#include +#include + +typedef u_int8_t qcdmbool; +#ifndef TRUE +#define TRUE ((u_int8_t) 1) +#endif +#ifndef FALSE +#define FALSE ((u_int8_t) 0) +#endif #define DIAG_CONTROL_CHAR 0x7E #define DIAG_TRAILER_LEN 3 -guint16 crc16 (const char *buffer, gsize len); +u_int16_t crc16 (const char *buffer, size_t len); -gsize dm_escape (const char *inbuf, - gsize inbuf_len, - char *outbuf, - gsize outbuf_len); +size_t dm_escape (const char *inbuf, + size_t inbuf_len, + char *outbuf, + size_t outbuf_len); -gsize dm_unescape (const char *inbuf, - gsize inbuf_len, - char *outbuf, - gsize outbuf_len, - gboolean *escaping); +size_t dm_unescape (const char *inbuf, + size_t inbuf_len, + char *outbuf, + size_t outbuf_len, + qcdmbool *escaping); -gsize dm_encapsulate_buffer (char *inbuf, - gsize cmd_len, - gsize inbuf_len, - char *outbuf, - gsize outbuf_len); +size_t dm_encapsulate_buffer (char *inbuf, + size_t cmd_len, + size_t inbuf_len, + char *outbuf, + size_t outbuf_len); -gboolean dm_decapsulate_buffer (const char *inbuf, - gsize inbuf_len, +qcdmbool dm_decapsulate_buffer (const char *inbuf, + size_t inbuf_len, char *outbuf, - gsize outbuf_len, - gsize *out_decap_len, - gsize *out_used, - gboolean *out_need_more); + size_t outbuf_len, + size_t *out_decap_len, + size_t *out_used, + qcdmbool *out_need_more); #endif /* UTILS_H */ diff --git a/libqcdm/tests/Makefile.am b/libqcdm/tests/Makefile.am index eb38fdb..322e016 100644 --- a/libqcdm/tests/Makefile.am +++ b/libqcdm/tests/Makefile.am @@ -1,5 +1,8 @@ +if WITH_TESTS + INCLUDES = \ - -I$(top_srcdir)/libqcdm/src + -I$(top_srcdir)/libqcdm/src \ + -I$(top_srcdir)/src noinst_PROGRAMS = test-qcdm @@ -16,14 +19,15 @@ test_qcdm_SOURCES = \ test-qcdm-result.h \ test-qcdm.c -test_qcdm_CPPFLAGS = \ - $(MM_CFLAGS) +test_qcdm_CPPFLAGS = $(MM_CFLAGS) -test_qcdm_LDADD = \ - $(top_builddir)/libqcdm/src/libqcdm.la \ - $(MM_LIBS) +test_qcdm_LDADD = $(MM_LIBS) -if WITH_TESTS +if QCDM_STANDALONE +test_qcdm_LDADD += $(top_builddir)/src/libqcdm.la +else +test_qcdm_LDADD += $(top_builddir)/libqcdm/src/libqcdm.la +endif check-local: test-qcdm $(abs_builddir)/test-qcdm diff --git a/libqcdm/tests/Makefile.in b/libqcdm/tests/Makefile.in index 18f649f..954764e 100644 --- a/libqcdm/tests/Makefile.in +++ b/libqcdm/tests/Makefile.in @@ -34,7 +34,9 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -noinst_PROGRAMS = test-qcdm$(EXEEXT) +@WITH_TESTS_TRUE@noinst_PROGRAMS = test-qcdm$(EXEEXT) +@QCDM_STANDALONE_TRUE@@WITH_TESTS_TRUE@am__append_1 = $(top_builddir)/src/libqcdm.la +@QCDM_STANDALONE_FALSE@@WITH_TESTS_TRUE@am__append_2 = $(top_builddir)/libqcdm/src/libqcdm.la subdir = libqcdm/tests DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -42,7 +44,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -50,16 +52,21 @@ CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) -am_test_qcdm_OBJECTS = test_qcdm-test-qcdm-crc.$(OBJEXT) \ - test_qcdm-test-qcdm-escaping.$(OBJEXT) \ - test_qcdm-test-qcdm-utils.$(OBJEXT) \ - test_qcdm-test-qcdm-com.$(OBJEXT) \ - test_qcdm-test-qcdm-result.$(OBJEXT) \ - test_qcdm-test-qcdm.$(OBJEXT) +am__test_qcdm_SOURCES_DIST = test-qcdm-crc.c test-qcdm-crc.h \ + test-qcdm-escaping.c test-qcdm-escaping.h test-qcdm-utils.c \ + test-qcdm-utils.h test-qcdm-com.c test-qcdm-com.h \ + test-qcdm-result.c test-qcdm-result.h test-qcdm.c +@WITH_TESTS_TRUE@am_test_qcdm_OBJECTS = \ +@WITH_TESTS_TRUE@ test_qcdm-test-qcdm-crc.$(OBJEXT) \ +@WITH_TESTS_TRUE@ test_qcdm-test-qcdm-escaping.$(OBJEXT) \ +@WITH_TESTS_TRUE@ test_qcdm-test-qcdm-utils.$(OBJEXT) \ +@WITH_TESTS_TRUE@ test_qcdm-test-qcdm-com.$(OBJEXT) \ +@WITH_TESTS_TRUE@ test_qcdm-test-qcdm-result.$(OBJEXT) \ +@WITH_TESTS_TRUE@ test_qcdm-test-qcdm.$(OBJEXT) test_qcdm_OBJECTS = $(am_test_qcdm_OBJECTS) am__DEPENDENCIES_1 = -test_qcdm_DEPENDENCIES = $(top_builddir)/libqcdm/src/libqcdm.la \ - $(am__DEPENDENCIES_1) +@WITH_TESTS_TRUE@test_qcdm_DEPENDENCIES = $(am__DEPENDENCIES_1) \ +@WITH_TESTS_TRUE@ $(am__append_1) $(am__append_2) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent @@ -90,7 +97,7 @@ AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(test_qcdm_SOURCES) -DIST_SOURCES = $(test_qcdm_SOURCES) +DIST_SOURCES = $(am__test_qcdm_SOURCES_DIST) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -245,29 +252,26 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -INCLUDES = \ - -I$(top_srcdir)/libqcdm/src - -test_qcdm_SOURCES = \ - test-qcdm-crc.c \ - test-qcdm-crc.h \ - test-qcdm-escaping.c \ - test-qcdm-escaping.h \ - test-qcdm-utils.c \ - test-qcdm-utils.h \ - test-qcdm-com.c \ - test-qcdm-com.h \ - test-qcdm-result.c \ - test-qcdm-result.h \ - test-qcdm.c - -test_qcdm_CPPFLAGS = \ - $(MM_CFLAGS) - -test_qcdm_LDADD = \ - $(top_builddir)/libqcdm/src/libqcdm.la \ - $(MM_LIBS) - +@WITH_TESTS_TRUE@INCLUDES = \ +@WITH_TESTS_TRUE@ -I$(top_srcdir)/libqcdm/src \ +@WITH_TESTS_TRUE@ -I$(top_srcdir)/src + +@WITH_TESTS_TRUE@test_qcdm_SOURCES = \ +@WITH_TESTS_TRUE@ test-qcdm-crc.c \ +@WITH_TESTS_TRUE@ test-qcdm-crc.h \ +@WITH_TESTS_TRUE@ test-qcdm-escaping.c \ +@WITH_TESTS_TRUE@ test-qcdm-escaping.h \ +@WITH_TESTS_TRUE@ test-qcdm-utils.c \ +@WITH_TESTS_TRUE@ test-qcdm-utils.h \ +@WITH_TESTS_TRUE@ test-qcdm-com.c \ +@WITH_TESTS_TRUE@ test-qcdm-com.h \ +@WITH_TESTS_TRUE@ test-qcdm-result.c \ +@WITH_TESTS_TRUE@ test-qcdm-result.h \ +@WITH_TESTS_TRUE@ test-qcdm.c + +@WITH_TESTS_TRUE@test_qcdm_CPPFLAGS = $(MM_CFLAGS) +@WITH_TESTS_TRUE@test_qcdm_LDADD = $(MM_LIBS) $(am__append_1) \ +@WITH_TESTS_TRUE@ $(am__append_2) all: all-am .SUFFIXES: diff --git a/libqcdm/tests/test-qcdm-com.c b/libqcdm/tests/test-qcdm-com.c index b95c7d9..65ce374 100644 --- a/libqcdm/tests/test-qcdm-com.c +++ b/libqcdm/tests/test-qcdm-com.c @@ -29,7 +29,7 @@ #include "utils.h" #include "result.h" #include "commands.h" -#include "error.h" +#include "errors.h" /************************************************************/ @@ -155,6 +155,55 @@ status_snapshot_state_to_string (guint8 state) return "unknown"; } +static const char * +cm_call_state_to_string (u_int32_t state) +{ + switch (state) { + case QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_IDLE: + return "idle"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_ORIGINATING: + return "originating"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_ALERTING: + return "alerting"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_ORIGINATION_ALERTING: + return "originating alerting"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_CALL_STATE_CONVERSATION: + return "conversation"; + default: + break; + } + return "unknown"; +} + +static const char * +cm_system_mode_to_string (u_int32_t mode) +{ + switch (mode) { + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_NO_SERVICE: + return "no service"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_AMPS: + return "AMPS"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_CDMA: + return "CDMA"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GSM: + return "GSM"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR: + return "HDR/EVDO"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA: + return "WCDMA"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GW: + return "GSM/WCDMA"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WLAN: + return "WLAN"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_LTE: + return "LTE"; + default: + break; + } + + return "unknown"; +} + /************************************************************/ typedef struct { @@ -293,7 +342,8 @@ wait_reply (TestComData *d, char *buf, gsize len) retries++; continue; } else if (bytes_read == 1) { - gboolean more = FALSE, success; + qcdmbool more = FALSE; + gboolean success; gsize used = 0; total++; @@ -328,17 +378,12 @@ void test_com_port_init (void *f, void *data) { TestComData *d = data; - GError *error = NULL; - gboolean success; + int err; - success = qcdm_port_setup (d->fd, &error); - if (!success) { - g_warning ("%s: error setting up port: (%d) %s", - d->port, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - } - g_assert (success); + err = qcdm_port_setup (d->fd); + if (err != QCDM_SUCCESS) + g_warning ("%s: error setting up port: %d", d->port, err); + g_assert (err == QCDM_SUCCESS); } void @@ -346,14 +391,13 @@ test_com_version_info (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; char buf[512]; const char *str; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; - len = qcdm_cmd_version_info_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_version_info_new (buf, sizeof (buf)); g_assert (len == 4); /* Send the command */ @@ -364,7 +408,7 @@ test_com_version_info (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_version_info_result (buf, reply_len, &error); + result = qcdm_cmd_version_info_result (buf, reply_len, NULL); g_assert (result); g_print ("\n"); @@ -397,14 +441,13 @@ test_com_esn (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; char buf[512]; const char *str; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; - len = qcdm_cmd_esn_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_esn_new (buf, sizeof (buf)); g_assert (len == 4); /* Send the command */ @@ -415,7 +458,7 @@ test_com_esn (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_esn_result (buf, reply_len, &error); + result = qcdm_cmd_esn_result (buf, reply_len, NULL); g_assert (result); g_print ("\n"); @@ -432,14 +475,14 @@ test_com_mdn (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; char buf[512]; const char *str; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; + int err = QCDM_SUCCESS; - len = qcdm_cmd_nv_get_mdn_new (buf, sizeof (buf), 0, NULL); + len = qcdm_cmd_nv_get_mdn_new (buf, sizeof (buf), 0); g_assert (len > 0); /* Send the command */ @@ -450,10 +493,14 @@ test_com_mdn (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_nv_get_mdn_result (buf, reply_len, &error); + result = qcdm_cmd_nv_get_mdn_result (buf, reply_len, &err); if (!result) { - g_assert_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_NVCMD_FAILED); - return; + if ( err == -QCDM_ERROR_NVCMD_FAILED + || err == -QCDM_ERROR_RESPONSE_BAD_PARAMETER + || err == -QCDM_ERROR_NV_ERROR_INACTIVE + || err == -QCDM_ERROR_NV_ERROR_BAD_PARAMETER) + return; + g_assert_cmpint (err, ==, QCDM_SUCCESS); } g_print ("\n"); @@ -470,15 +517,15 @@ test_com_read_roam_pref (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[512]; guint8 pref; const char *msg; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; - len = qcdm_cmd_nv_get_roam_pref_new (buf, sizeof (buf), 0, NULL); + len = qcdm_cmd_nv_get_roam_pref_new (buf, sizeof (buf), 0); g_assert (len > 0); /* Send the command */ @@ -489,16 +536,21 @@ test_com_read_roam_pref (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_nv_get_roam_pref_result (buf, reply_len, &error); - if (error && (error->code == QCDM_COMMAND_NVCMD_FAILED)) - return; - + result = qcdm_cmd_nv_get_roam_pref_result (buf, reply_len, &err); + if (!result) { + if ( err == -QCDM_ERROR_NVCMD_FAILED + || err == -QCDM_ERROR_RESPONSE_BAD_PARAMETER + || err == -QCDM_ERROR_NV_ERROR_INACTIVE + || err == -QCDM_ERROR_NV_ERROR_BAD_PARAMETER) + return; + g_assert_cmpint (err, ==, QCDM_SUCCESS); + } g_assert (result); g_print ("\n"); - success = qcdm_result_get_uint8 (result, QCDM_CMD_NV_GET_ROAM_PREF_ITEM_ROAM_PREF, &pref); - g_assert (success); + err = qcdm_result_get_u8 (result, QCDM_CMD_NV_GET_ROAM_PREF_ITEM_ROAM_PREF, &pref); + g_assert_cmpint (err, ==, QCDM_SUCCESS); switch (pref) { case QCDM_CMD_NV_ROAM_PREF_ITEM_ROAM_PREF_HOME_ONLY: @@ -523,15 +575,15 @@ test_com_read_mode_pref (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[512]; guint8 pref; const char *msg; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; - len = qcdm_cmd_nv_get_mode_pref_new (buf, sizeof (buf), 0, NULL); + len = qcdm_cmd_nv_get_mode_pref_new (buf, sizeof (buf), 0); g_assert (len > 0); /* Send the command */ @@ -542,28 +594,45 @@ test_com_read_mode_pref (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_nv_get_mode_pref_result (buf, reply_len, &error); + result = qcdm_cmd_nv_get_mode_pref_result (buf, reply_len, &err); if (!result) { - g_assert (error); - g_assert (error->domain == QCDM_COMMAND_ERROR); - g_assert (error->code == QCDM_COMMAND_NVCMD_FAILED || error->code == QCDM_COMMAND_BAD_PARAMETER); - return; + if ( err == -QCDM_ERROR_NVCMD_FAILED + || err == -QCDM_ERROR_RESPONSE_BAD_PARAMETER + || err == -QCDM_ERROR_NV_ERROR_INACTIVE + || err == -QCDM_ERROR_NV_ERROR_BAD_PARAMETER) + return; + g_assert_cmpint (err, ==, QCDM_SUCCESS); } g_print ("\n"); - success = qcdm_result_get_uint8 (result, QCDM_CMD_NV_GET_MODE_PREF_ITEM_MODE_PREF, &pref); - g_assert (success); + err = qcdm_result_get_u8 (result, QCDM_CMD_NV_GET_MODE_PREF_ITEM_MODE_PREF, &pref); + g_assert_cmpint (err, ==, QCDM_SUCCESS); switch (pref) { + case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_DIGITAL: + msg = "digital"; + break; + case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_DIGITAL_ONLY: + msg = "digital only"; + break; + case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_AUTO: + msg = "automatic"; + break; case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_1X_ONLY: - msg = "1X only"; + msg = "CDMA 1x only"; break; case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_HDR_ONLY: msg = "HDR only"; break; - case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_AUTO: - msg = "automatic"; + case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_1X_HDR_ONLY: + msg = "CDMA 1x and HDR only"; + break; + case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_LTE_ONLY: + msg = "LTE only"; + break; + case QCDM_CMD_NV_MODE_PREF_ITEM_MODE_PREF_1X_HDR_LTE_ONLY: + msg = "CDMA 1x, HDR, and LTE only"; break; default: msg = "unknown"; @@ -579,15 +648,15 @@ test_com_read_hdr_rev_pref (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[512]; guint8 pref; const char *msg; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; - len = qcdm_cmd_nv_get_hdr_rev_pref_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_nv_get_hdr_rev_pref_new (buf, sizeof (buf)); g_assert (len > 0); /* Send the command */ @@ -598,18 +667,20 @@ test_com_read_hdr_rev_pref (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_nv_get_hdr_rev_pref_result (buf, reply_len, &error); + result = qcdm_cmd_nv_get_hdr_rev_pref_result (buf, reply_len, &err); if (!result) { - g_assert (error); - g_assert (error->domain == QCDM_COMMAND_ERROR); - g_assert (error->code == QCDM_COMMAND_NVCMD_FAILED || error->code == QCDM_COMMAND_BAD_PARAMETER); - return; + if ( err == -QCDM_ERROR_NVCMD_FAILED + || err == -QCDM_ERROR_RESPONSE_BAD_PARAMETER + || err == -QCDM_ERROR_NV_ERROR_INACTIVE + || err == -QCDM_ERROR_NV_ERROR_BAD_PARAMETER) + return; + g_assert_cmpint (err, ==, QCDM_SUCCESS); } g_print ("\n"); - success = qcdm_result_get_uint8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, &pref); - g_assert (success); + err = qcdm_result_get_u8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, &pref); + g_assert_cmpint (err, ==, QCDM_SUCCESS); switch (pref) { case QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_0: @@ -635,16 +706,16 @@ test_com_status (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[100]; const char *str, *detail; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; guint32 n32; guint8 n8; - len = qcdm_cmd_cdma_status_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_cdma_status_new (buf, sizeof (buf)); g_assert (len == 4); /* Send the command */ @@ -655,7 +726,12 @@ test_com_status (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_cdma_status_result (buf, reply_len, &error); + result = qcdm_cmd_cdma_status_result (buf, reply_len, &err); + if (!result) { + /* WCDMA/GSM devices don't implement this command */ + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); + return; + } g_assert (result); g_print ("\n"); @@ -666,7 +742,7 @@ test_com_status (void *f, void *data) n32 = 0; detail = NULL; - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RF_MODE, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RF_MODE, &n32); switch (n32) { case QCDM_CMD_CDMA_STATUS_RF_MODE_ANALOG: detail = "analog"; @@ -694,7 +770,7 @@ test_com_status (void *f, void *data) n32 = 0; detail = NULL; - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RX_STATE, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RX_STATE, &n32); switch (n32) { case QCDM_CMD_CDMA_STATUS_RX_STATE_ENTERING_CDMA: detail = "entering CDMA"; @@ -721,27 +797,27 @@ test_com_status (void *f, void *data) g_message ("%s: CDMA RX State: %u (%s)", __func__, n32, detail); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_ENTRY_REASON, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_ENTRY_REASON, &n32); g_message ("%s: Entry Reason: %u", __func__, n32); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_CURRENT_CHANNEL, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_CURRENT_CHANNEL, &n32); g_message ("%s: Current Channel: %u", __func__, n32); n8 = 0; - qcdm_result_get_uint8 (result, QCDM_CMD_CDMA_STATUS_ITEM_CODE_CHANNEL, &n8); + qcdm_result_get_u8 (result, QCDM_CMD_CDMA_STATUS_ITEM_CODE_CHANNEL, &n8); g_message ("%s: Code Channel: %u", __func__, n8); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_PILOT_BASE, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_PILOT_BASE, &n32); g_message ("%s: Pilot Base: %u", __func__, n32); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_SID, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_SID, &n32); g_message ("%s: CDMA System ID: %u", __func__, n32); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_NID, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_NID, &n32); g_message ("%s: CDMA Network ID: %u", __func__, n32); qcdm_result_unref (result); @@ -752,13 +828,14 @@ test_com_sw_version (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[100]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; + const char *str; - len = qcdm_cmd_sw_version_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_sw_version_new (buf, sizeof (buf)); g_assert (len == 4); /* Send the command */ @@ -769,13 +846,12 @@ test_com_sw_version (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_sw_version_result (buf, reply_len, &error); - - /* Recent devices don't appear to implement this command */ - g_assert (result == NULL); - g_assert_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_COMMAND); + result = qcdm_cmd_sw_version_result (buf, reply_len, &err); + if (!result) { + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); + return; + } -/* str = NULL; qcdm_result_get_string (result, QCDM_CMD_SW_VERSION_ITEM_VERSION, &str); g_message ("%s: SW Version: %s", __func__, str); @@ -789,7 +865,6 @@ test_com_sw_version (void *f, void *data) g_message ("%s: Compiled Time: %s", __func__, str); qcdm_result_unref (result); -*/ } void @@ -797,14 +872,14 @@ test_com_status_snapshot (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[100]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; guint8 n8; - len = qcdm_cmd_status_snapshot_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_status_snapshot_new (buf, sizeof (buf)); g_assert (len == 4); /* Send the command */ @@ -815,29 +890,34 @@ test_com_status_snapshot (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_status_snapshot_result (buf, reply_len, &error); + result = qcdm_cmd_status_snapshot_result (buf, reply_len, &err); + if (!result) { + /* WCDMA/GSM devices don't implement this command */ + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); + return; + } g_assert (result); g_print ("\n"); n8 = 0; - qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BAND_CLASS, &n8); + qcdm_result_get_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BAND_CLASS, &n8); g_message ("%s: Band Class: %s", __func__, band_class_to_string (n8)); n8 = 0; - qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BASE_STATION_PREV, &n8); + qcdm_result_get_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BASE_STATION_PREV, &n8); g_message ("%s: Base station P_REV: %s", __func__, prev_to_string (n8)); n8 = 0; - qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_MOBILE_PREV, &n8); + qcdm_result_get_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_MOBILE_PREV, &n8); g_message ("%s: Mobile P_REV: %s", __func__, prev_to_string (n8)); n8 = 0; - qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_PREV_IN_USE, &n8); + qcdm_result_get_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_PREV_IN_USE, &n8); g_message ("%s: P_REV in-use: %s", __func__, prev_to_string (n8)); n8 = 0; - qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE, &n8); + qcdm_result_get_u8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE, &n8); g_message ("%s: State: %d (%s)", __func__, n8, status_snapshot_state_to_string (n8)); qcdm_result_unref (result); @@ -848,14 +928,14 @@ test_com_pilot_sets (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[256]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; guint32 num, i; - len = qcdm_cmd_pilot_sets_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_pilot_sets_new (buf, sizeof (buf)); g_assert (len == 4); /* Send the command */ @@ -866,7 +946,12 @@ test_com_pilot_sets (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_pilot_sets_result (buf, reply_len, &error); + result = qcdm_cmd_pilot_sets_result (buf, reply_len, &err); + if (!result) { + /* WCDMA/GSM devices don't implement this command */ + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); + return; + } g_assert (result); num = 0; @@ -897,20 +982,45 @@ test_com_pilot_sets (void *f, void *data) qcdm_result_unref (result); } +static const char * +operating_mode_to_string (guint32 mode) +{ + switch (mode) { + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_POWER_OFF: + return "powering off"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_FIELD_TEST_MODE: + return "field test mode"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_OFFLINE: + return "offline"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_OFFLINE_AMPS: + return "online (AMPS)"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_OFFLINE_CDMA: + return "online (CDMA)"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE: + return "online"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_LOW_POWER_MODE: + return "low power mode"; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_RESET: + return "reset"; + default: + return "unknown"; + } +} + void test_com_cm_subsys_state_info (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[100]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; guint32 n32; const char *detail; - len = qcdm_cmd_cm_subsys_state_info_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_cm_subsys_state_info_new (buf, sizeof (buf)); g_assert (len == 7); /* Send the command */ @@ -921,58 +1031,27 @@ test_com_cm_subsys_state_info (void *f, void *data) reply_len = wait_reply (d, buf, sizeof (buf)); /* Parse the response into a result structure */ - result = qcdm_cmd_cm_subsys_state_info_result (buf, reply_len, &error); + result = qcdm_cmd_cm_subsys_state_info_result (buf, reply_len, &err); g_assert (result); g_print ("\n"); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_CALL_STATE, &n32); - g_message ("%s: Call State: %u", __func__, n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_CALL_STATE, &n32); + g_message ("%s: Call State: %u (%s)", __func__, n32, cm_call_state_to_string (n32)); n32 = 0; detail = NULL; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &n32); - switch (n32) { - case QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE: - detail = "online"; - break; - default: - detail = "unknown"; - break; - } - g_message ("%s: Operating Mode: %u (%s)", __func__, n32, detail); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &n32); + g_message ("%s: Operating Mode: %u (%s)", __func__, n32, operating_mode_to_string (n32)); n32 = 0; detail = NULL; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &n32); - switch (n32) { - case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_NO_SERVICE: - detail = "no service"; - break; - case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_AMPS: - detail = "AMPS"; - break; - case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_CDMA: - detail = "CDMA"; - break; - case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR: - detail = "HDR/EVDO"; - break; - case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA: - detail = "WCDMA"; - break; - case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_LTE: - detail = "LTE"; - break; - default: - detail = "unknown"; - break; - } - g_message ("%s: System Mode: %u (%s)", __func__, n32, detail); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &n32); + g_message ("%s: System Mode: %u (%s)", __func__, n32, cm_system_mode_to_string (n32)); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_MODE_PREF, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_MODE_PREF, &n32); switch (n32) { case QCDM_CMD_CM_SUBSYS_STATE_INFO_MODE_PREF_DIGITAL_ONLY: detail = "digital only"; @@ -993,11 +1072,11 @@ test_com_cm_subsys_state_info (void *f, void *data) g_message ("%s: Mode Preference: 0x%02X (%s)", __func__, n32 & 0xFF, detail); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_BAND_PREF, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_BAND_PREF, &n32); g_message ("%s: Band Preference: %u", __func__, n32); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ROAM_PREF, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ROAM_PREF, &n32); switch (n32) { case QCDM_CMD_CM_SUBSYS_STATE_INFO_ROAM_PREF_HOME_ONLY: detail = "home only"; @@ -1014,19 +1093,19 @@ test_com_cm_subsys_state_info (void *f, void *data) g_message ("%s: Roam Preference: 0x%02X (%s)", __func__, n32 & 0xFF, detail); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SERVICE_DOMAIN_PREF, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SERVICE_DOMAIN_PREF, &n32); g_message ("%s: Service Domain Preference: %u", __func__, n32); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ACQ_ORDER_PREF, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ACQ_ORDER_PREF, &n32); g_message ("%s: Acquisition Order Preference: %u", __func__, n32); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_HYBRID_PREF, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_HYBRID_PREF, &n32); g_message ("%s: Hybrid Preference: %u", __func__, n32); n32 = 0; - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_NETWORK_SELECTION_PREF, &n32); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_NETWORK_SELECTION_PREF, &n32); g_message ("%s: Network Selection Preference: %u", __func__, n32); qcdm_result_unref (result); @@ -1037,15 +1116,15 @@ test_com_hdr_subsys_state_info (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[100]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; guint8 num; const char *detail; - len = qcdm_cmd_hdr_subsys_state_info_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_hdr_subsys_state_info_new (buf, sizeof (buf)); g_assert (len == 7); /* Send the command */ @@ -1058,10 +1137,10 @@ test_com_hdr_subsys_state_info (void *f, void *data) g_print ("\n"); /* Parse the response into a result structure */ - result = qcdm_cmd_hdr_subsys_state_info_result (buf, reply_len, &error); + result = qcdm_cmd_hdr_subsys_state_info_result (buf, reply_len, &err); if (!result) { /* 1x-only devices won't implement the HDR subsystem of course */ - g_assert_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_COMMAND); + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); g_message ("%s: device does not implement the HDR subsystem", __func__); return; } @@ -1069,7 +1148,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_AT_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_AT_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_AT_STATE_INACTIVE: detail = "inactive"; @@ -1097,7 +1176,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_SESSION_STATE_CLOSED: detail = "closed"; @@ -1125,7 +1204,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_INACTIVE: detail = "inactive"; @@ -1147,7 +1226,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_INIT_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_INIT_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_INIT_STATE_INACTIVE: detail = "inactive"; @@ -1169,7 +1248,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_IDLE_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_IDLE_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_IDLE_STATE_INACTIVE: detail = "inactive"; @@ -1191,7 +1270,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_CONNECTED_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_CONNECTED_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_CONNECTED_STATE_INACTIVE: detail = "inactive"; @@ -1210,7 +1289,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ROUTE_UPDATE_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ROUTE_UPDATE_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_ROUTE_UPDATE_STATE_INACTIVE: detail = "inactive"; @@ -1229,7 +1308,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) num = 0; detail = NULL; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_OVERHEAD_MSG_STATE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_OVERHEAD_MSG_STATE, &num); switch (num) { case QCDM_CMD_HDR_SUBSYS_STATE_INFO_OVERHEAD_MSG_STATE_INIT: detail = "initial"; @@ -1247,7 +1326,7 @@ test_com_hdr_subsys_state_info (void *f, void *data) g_message ("%s: Overhead Msg State: %u (%s)", __func__, num, detail); num = 0; - qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, &num); + qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, &num); g_message ("%s: HDR Hybrid Mode: %u", __func__, num); qcdm_result_unref (result); @@ -1258,16 +1337,16 @@ test_com_ext_logmask (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[520]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; - GSList *items = NULL; + u_int32_t items[] = { 0x002C, 0x002E, 0 }; guint32 maxlog = 0; /* First get # of items the device supports */ - len = qcdm_cmd_ext_logmask_new (buf, sizeof (buf), NULL, 0, NULL); + len = qcdm_cmd_ext_logmask_new (buf, sizeof (buf), NULL, 0); /* Send the command */ success = send_command (d, buf, len); @@ -1279,19 +1358,16 @@ test_com_ext_logmask (void *f, void *data) g_print ("\n"); /* Parse the response into a result structure */ - result = qcdm_cmd_ext_logmask_result (buf, reply_len, &error); + result = qcdm_cmd_ext_logmask_result (buf, reply_len, &err); g_assert (result); - qcdm_result_get_uint32 (result, QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS, &maxlog); + qcdm_result_get_u32 (result, QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS, &maxlog); g_message ("%s: Max # Log Items: %u (0x%X)", __func__, maxlog, maxlog); qcdm_result_unref (result); /* Now enable some log items */ - items = g_slist_append (items, GUINT_TO_POINTER (0x002C)); - items = g_slist_append (items, GUINT_TO_POINTER (0x002E)); - len = qcdm_cmd_ext_logmask_new (buf, sizeof (buf), items, (guint16) maxlog, NULL); - g_slist_free (items); + len = qcdm_cmd_ext_logmask_new (buf, sizeof (buf), items, (u_int16_t) maxlog); /* Send the command */ success = send_command (d, buf, len); @@ -1303,7 +1379,7 @@ test_com_ext_logmask (void *f, void *data) g_print ("\n"); /* Parse the response into a result structure */ - result = qcdm_cmd_ext_logmask_result (buf, reply_len, &error); + result = qcdm_cmd_ext_logmask_result (buf, reply_len, &err); g_assert (result); qcdm_result_unref (result); @@ -1317,14 +1393,15 @@ test_com_event_report (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[520]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; + guint32 i; /* Turn event reporting on */ - len = qcdm_cmd_event_report_new (buf, sizeof (buf), TRUE, NULL); + len = qcdm_cmd_event_report_new (buf, sizeof (buf), TRUE); /* Send the command */ success = send_command (d, buf, len); @@ -1336,16 +1413,91 @@ test_com_event_report (void *f, void *data) g_print ("\n"); /* Parse the response into a result structure */ - result = qcdm_cmd_event_report_result (buf, reply_len, &error); + result = qcdm_cmd_event_report_result (buf, reply_len, &err); g_assert (result); qcdm_result_unref (result); - /* Wait for an event */ - reply_len = wait_reply (d, buf, sizeof (buf)); + /* Wait for a few events */ + for (i = 0; i < 4; i++) + reply_len = wait_reply (d, buf, sizeof (buf)); /* Turn event reporting off */ - len = qcdm_cmd_event_report_new (buf, sizeof (buf), FALSE, NULL); + len = qcdm_cmd_event_report_new (buf, sizeof (buf), FALSE); + + /* Send the command */ + success = send_command (d, buf, len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); +} + +void +test_com_log_config (void *f, void *data) +{ + TestComData *d = data; + gboolean success; + int err = QCDM_SUCCESS; + char buf[520]; + gint len; + QcdmResult *result; + gsize reply_len; + u_int32_t num_items = 0; + const u_int16_t *items = NULL, *reread_items; + size_t items_len = 0, reread_len; + u_int32_t i; + u_int16_t test_items[] = { 0x1004, 0x1005, 0x1006, 0x1007, 0x1008, 0x102C, 0x102E, 0 }; + + /* Get existing mask for CDMA/EVDO equip ID */ + len = qcdm_cmd_log_config_get_mask_new (buf, sizeof (buf), 0x01); + g_assert (len); + + /* Send the command */ + success = send_command (d, buf, len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); + + g_print ("\n"); + + /* Parse the response into a result structure */ + result = qcdm_cmd_log_config_get_mask_result (buf, reply_len, &err); + g_assert (result); + + qcdm_result_get_u32 (result, QCDM_CMD_LOG_CONFIG_MASK_ITEM_NUM_ITEMS, &num_items); + g_message ("%s: Num Log Items: %u (0x%X)", __func__, num_items, num_items); + + qcdm_result_get_u16_array (result, QCDM_CMD_LOG_CONFIG_MASK_ITEM_ITEMS, + &items, &items_len); + for (i = 0; i < items_len; i++) + g_message ("%s: Enabled: 0x%04x", __func__, items[i]); + + qcdm_result_unref (result); + + /* Turn on some log messages */ + len = qcdm_cmd_log_config_set_mask_new (buf, sizeof (buf), 0x01, test_items); + g_assert (len); + + /* Send the command */ + success = send_command (d, buf, len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); + + g_print ("\n"); + + /* Parse the response into a result structure */ + result = qcdm_cmd_log_config_set_mask_result (buf, reply_len, &err); + g_assert (result); + + qcdm_result_unref (result); + + /* Get the mask again so we can compare it to what we just set */ + len = qcdm_cmd_log_config_get_mask_new (buf, sizeof (buf), 0x01); + g_assert (len); /* Send the command */ success = send_command (d, buf, len); @@ -1353,6 +1505,23 @@ test_com_event_report (void *f, void *data) /* Get a response */ reply_len = wait_reply (d, buf, sizeof (buf)); + + g_print ("\n"); + + /* Parse the response into a result structure */ + result = qcdm_cmd_log_config_get_mask_result (buf, reply_len, &err); + g_assert (result); + + qcdm_result_get_u16_array (result, QCDM_CMD_LOG_CONFIG_MASK_ITEM_ITEMS, + &reread_items, &reread_len); + g_assert_cmpint (reread_len, ==, (sizeof (test_items) - 1) / sizeof (test_items[0])); + g_assert (memcmp (reread_items, test_items, reread_len * sizeof (test_items[0])) == 0); + + qcdm_result_unref (result); + + /* Wait for a few log packets */ + for (i = 0; i < 5; i++) + reply_len = wait_reply (d, buf, sizeof (buf)); } void @@ -1360,14 +1529,14 @@ test_com_zte_subsys_status (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[100]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; guint8 ind = 0; - len = qcdm_cmd_zte_subsys_status_new (buf, sizeof (buf), NULL); + len = qcdm_cmd_zte_subsys_status_new (buf, sizeof (buf)); g_assert (len == 7); /* Send the command */ @@ -1380,16 +1549,16 @@ test_com_zte_subsys_status (void *f, void *data) g_print ("\n"); /* Parse the response into a result structure */ - result = qcdm_cmd_zte_subsys_status_result (buf, reply_len, &error); + result = qcdm_cmd_zte_subsys_status_result (buf, reply_len, &err); if (!result) { /* Obviously not all devices implement this command */ - g_assert_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_COMMAND); + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); g_message ("%s: device does not implement the ZTE subsystem", __func__); return; } g_assert (result); - qcdm_result_get_uint8 (result, QCDM_CMD_ZTE_SUBSYS_STATUS_ITEM_SIGNAL_INDICATOR, &ind); + qcdm_result_get_u8 (result, QCDM_CMD_ZTE_SUBSYS_STATUS_ITEM_SIGNAL_INDICATOR, &ind); g_message ("%s: Signal Indicator: %d", __func__, ind); qcdm_result_unref (result); @@ -1400,15 +1569,15 @@ test_com_nw_subsys_modem_snapshot_cdma (void *f, void *data) { TestComData *d = data; gboolean success; - GError *error = NULL; + int err = QCDM_SUCCESS; char buf[200]; gint len; - QCDMResult *result; + QcdmResult *result; gsize reply_len; guint8 num8 = 0; guint32 num32 = 0; - len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new (buf, sizeof (buf), QCDM_NW_CHIPSET_6800, NULL); + len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new (buf, sizeof (buf), QCDM_NW_CHIPSET_6800); g_assert (len == 12); /* Send the command */ @@ -1421,29 +1590,192 @@ test_com_nw_subsys_modem_snapshot_cdma (void *f, void *data) g_print ("\n"); /* Parse the response into a result structure */ - result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result (buf, reply_len, &error); + result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result (buf, reply_len, &err); if (!result) { /* Obviously not all devices implement this command */ - g_assert_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_COMMAND); + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); return; } g_assert (result); - qcdm_result_get_uint32 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_RSSI, &num32); + qcdm_result_get_u32 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_RSSI, &num32); g_message ("%s: RSSI: %d", __func__, num32); - qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_PREV, &num8); + qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_PREV, &num8); g_message ("%s: P_REV: %s", __func__, prev_to_string (num8)); - qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_BAND_CLASS, &num8); + qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_BAND_CLASS, &num8); g_message ("%s: Band Class: %s", __func__, band_class_to_string (num8)); - qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &num8); + qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &num8); g_message ("%s: ERI: %d", __func__, num8); - qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_HDR_REV, &num8); + qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_HDR_REV, &num8); g_message ("%s: HDR Revision: %s", __func__, hdr_rev_to_string (num8)); qcdm_result_unref (result); } +void +test_com_wcdma_subsys_state_info (void *f, void *data) +{ + TestComData *d = data; + gboolean success; + int err = QCDM_SUCCESS; + char buf[200]; + gint len; + QcdmResult *result; + gsize reply_len; + guint8 num8 = 0; + const char *str; + + len = qcdm_cmd_wcdma_subsys_state_info_new (buf, sizeof (buf)); + g_assert (len == 7); + + /* Send the command */ + success = send_command (d, buf, len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); + + g_print ("\n"); + + /* Parse the response into a result structure */ + result = qcdm_cmd_wcdma_subsys_state_info_result (buf, reply_len, &err); + if (!result) { + /* Obviously not all devices implement this command */ + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); + return; + } + g_assert (result); + + str = NULL; + qcdm_result_get_string (result, QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_IMEI, &str); + g_message ("%s: IMEI: %s", __func__, str); + + str = NULL; + qcdm_result_get_string (result, QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_IMSI, &str); + g_message ("%s: IMSI: %s", __func__, str); + + str = "unknown"; + qcdm_result_get_u8 (result, QCDM_CMD_WCDMA_SUBSYS_STATE_INFO_ITEM_L1_STATE, &num8); + switch (num8) { + case QCDM_WCDMA_L1_STATE_INIT: + str = "Init"; + break; + case QCDM_WCDMA_L1_STATE_IDLE: + str = "Idle"; + break; + case QCDM_WCDMA_L1_STATE_FS: + str = "FS"; + break; + case QCDM_WCDMA_L1_STATE_ACQ: + str = "ACQ"; + break; + case QCDM_WCDMA_L1_STATE_BCH: + str = "BCH"; + break; + case QCDM_WCDMA_L1_STATE_PCH: + str = "PCH"; + break; + case QCDM_WCDMA_L1_STATE_FACH: + str = "FACH"; + break; + case QCDM_WCDMA_L1_STATE_DCH: + str = "DCH"; + break; + case QCDM_WCDMA_L1_STATE_DEACTIVATE: + str = "Deactivated"; + break; + case QCDM_WCDMA_L1_STATE_DEEP_SLEEP: + str = "Deep Sleep"; + break; + case QCDM_WCDMA_L1_STATE_STOPPED: + str = "Stopped"; + break; + case QCDM_WCDMA_L1_STATE_SUSPENDED: + str = "Suspended"; + break; + default: + break; + } + g_message ("%s: L1 state: %d (%s)", __func__, num8, str); + + qcdm_result_unref (result); +} + +void +test_com_gsm_subsys_state_info (void *f, void *data) +{ + TestComData *d = data; + gboolean success; + int err = QCDM_SUCCESS; + char buf[200]; + gint len; + QcdmResult *result; + gsize reply_len; + const char *str; + u_int32_t num; + u_int8_t u8; + + len = qcdm_cmd_gsm_subsys_state_info_new (buf, sizeof (buf)); + g_assert (len == 7); + + /* Send the command */ + success = send_command (d, buf, len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); + + g_print ("\n"); + + /* Parse the response into a result structure */ + result = qcdm_cmd_gsm_subsys_state_info_result (buf, reply_len, &err); + if (!result) { + /* Obviously not all devices implement this command */ + g_assert_cmpint (err, ==, -QCDM_ERROR_RESPONSE_BAD_COMMAND); + return; + } + g_assert (result); + + str = NULL; + qcdm_result_get_string (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_IMEI, &str); + g_message ("%s: IMEI: %s", __func__, str); + + str = NULL; + qcdm_result_get_string (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_IMSI, &str); + g_message ("%s: IMSI: %s", __func__, str); + + num = 0; + qcdm_result_get_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_MCC, &num); + g_message ("%s: MCC: %d", __func__, num); + + num = 0; + qcdm_result_get_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_MNC, &num); + g_message ("%s: MNC: %d", __func__, num); + + num = 0; + qcdm_result_get_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_LAI_LAC, &num); + g_message ("%s: LAC: 0x%04X", __func__, num); + + num = 0; + qcdm_result_get_u32 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CELLID, &num); + g_message ("%s: Cell ID: 0x%04X", __func__, num); + + u8 = 0; + qcdm_result_get_u8 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_CALL_STATE, &u8); + g_message ("%s: CM Call State: %d (%s)", __func__, u8, cm_call_state_to_string (u8)); + + u8 = 0; + qcdm_result_get_u8 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_OP_MODE, &u8); + g_message ("%s: CM Opmode: %d (%s)", __func__, u8, operating_mode_to_string (u8)); + + u8 = 0; + qcdm_result_get_u8 (result, QCDM_CMD_GSM_SUBSYS_STATE_INFO_ITEM_CM_SYS_MODE, &u8); + g_message ("%s: CM Sysmode: %d (%s)", __func__, u8, cm_system_mode_to_string (u8)); + + qcdm_result_unref (result); +} + diff --git a/libqcdm/tests/test-qcdm-com.h b/libqcdm/tests/test-qcdm-com.h index 76075e5..57e00b0 100644 --- a/libqcdm/tests/test-qcdm-com.h +++ b/libqcdm/tests/test-qcdm-com.h @@ -51,9 +51,15 @@ void test_com_ext_logmask (void *f, void *data); void test_com_event_report (void *f, void *data); +void test_com_log_config (void *f, void *data); + void test_com_zte_subsys_status (void *f, void *data); void test_com_nw_subsys_modem_snapshot_cdma (void *f, void *data); +void test_com_wcdma_subsys_state_info (void *f, void *data); + +void test_com_gsm_subsys_state_info (void *f, void *data); + #endif /* TEST_QCDM_COM_H */ diff --git a/libqcdm/tests/test-qcdm-escaping.c b/libqcdm/tests/test-qcdm-escaping.c index fb5fb82..0f40307 100644 --- a/libqcdm/tests/test-qcdm-escaping.c +++ b/libqcdm/tests/test-qcdm-escaping.c @@ -110,7 +110,7 @@ test_escape_unescape (void *f, void *data) char escaped[512]; char unescaped[512]; gsize len, unlen; - gboolean escaping = FALSE; + qcdmbool escaping = FALSE; /* Ensure that escaping data that needs escaping, and then unescaping it, * produces the exact same data as was originally escaped. diff --git a/libqcdm/tests/test-qcdm-result.c b/libqcdm/tests/test-qcdm-result.c index 87f264b..0a1820d 100644 --- a/libqcdm/tests/test-qcdm-result.c +++ b/libqcdm/tests/test-qcdm-result.c @@ -29,7 +29,7 @@ test_result_string (void *f, void *data) { const char *str = "foobarblahblahblah"; const char *tmp = NULL; - QCDMResult *result; + QcdmResult *result; result = qcdm_result_new (); qcdm_result_add_string (result, TEST_TAG, str); @@ -46,13 +46,13 @@ test_result_uint32 (void *f, void *data) { guint32 num = 0xDEADBEEF; guint32 tmp = 0; - QCDMResult *result; + QcdmResult *result; result = qcdm_result_new (); - qcdm_result_add_uint32 (result, TEST_TAG, num); + qcdm_result_add_u32 (result, TEST_TAG, num); - qcdm_result_get_uint32 (result, TEST_TAG, &tmp); - g_assert (tmp == num); + qcdm_result_get_u32 (result, TEST_TAG, &tmp); + g_assert_cmpint (tmp, ==, num); } void @@ -60,12 +60,28 @@ test_result_uint8 (void *f, void *data) { guint8 num = 0x1E; guint8 tmp = 0; - QCDMResult *result; + QcdmResult *result; result = qcdm_result_new (); - qcdm_result_add_uint8 (result, TEST_TAG, num); + qcdm_result_add_u8 (result, TEST_TAG, num); - qcdm_result_get_uint8 (result, TEST_TAG, &tmp); + qcdm_result_get_u8 (result, TEST_TAG, &tmp); g_assert (tmp == num); } +void +test_result_uint8_array (void *f, void *data) +{ + u_int8_t array[] = { 0, 1, 255, 32, 128, 127 }; + const u_int8_t *tmp = NULL; + size_t tmp_len = 0; + QcdmResult *result; + + result = qcdm_result_new (); + qcdm_result_add_u8_array (result, TEST_TAG, array, sizeof (array)); + + qcdm_result_get_u8_array (result, TEST_TAG, &tmp, &tmp_len); + g_assert_cmpint (tmp_len, ==, sizeof (array)); + g_assert_cmpint (memcmp (tmp, array, tmp_len), ==, 0); +} + diff --git a/libqcdm/tests/test-qcdm-result.h b/libqcdm/tests/test-qcdm-result.h index 20d6cec..3ab718b 100644 --- a/libqcdm/tests/test-qcdm-result.h +++ b/libqcdm/tests/test-qcdm-result.h @@ -21,6 +21,7 @@ void test_result_string (void *f, void *data); void test_result_uint32 (void *f, void *data); void test_result_uint8 (void *f, void *data); +void test_result_uint8_array (void *f, void *data); #endif /* TEST_QCDM_RESULT_H */ diff --git a/libqcdm/tests/test-qcdm-utils.c b/libqcdm/tests/test-qcdm-utils.c index 04807c1..4771838 100644 --- a/libqcdm/tests/test-qcdm-utils.c +++ b/libqcdm/tests/test-qcdm-utils.c @@ -50,7 +50,7 @@ test_utils_decapsulate_buffer (void *f, void *data) char outbuf[512]; gsize decap_len = 0; gsize used = 0; - gboolean more = FALSE; + qcdmbool more = FALSE; success = dm_decapsulate_buffer (decap_inbuf, sizeof (decap_inbuf), outbuf, sizeof (outbuf), @@ -96,7 +96,7 @@ test_utils_decapsulate_sierra_cns (void *f, void *data) char outbuf[512]; gsize decap_len = 0; gsize used = 0; - gboolean more = FALSE; + qcdmbool more = FALSE; success = dm_decapsulate_buffer (cns_inbuf, sizeof (cns_inbuf), outbuf, sizeof (outbuf), diff --git a/libqcdm/tests/test-qcdm.c b/libqcdm/tests/test-qcdm.c index 946fb67..8d25d82 100644 --- a/libqcdm/tests/test-qcdm.c +++ b/libqcdm/tests/test-qcdm.c @@ -93,6 +93,7 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_result_string, NULL)); g_test_suite_add (suite, TESTCASE (test_result_uint32, NULL)); g_test_suite_add (suite, TESTCASE (test_result_uint8, NULL)); + g_test_suite_add (suite, TESTCASE (test_result_uint8_array, NULL)); /* Live tests */ if (port) { @@ -111,8 +112,11 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_com_hdr_subsys_state_info, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_ext_logmask, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_event_report, data->com_data)); + g_test_suite_add (suite, TESTCASE (test_com_log_config, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_zte_subsys_status, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_nw_subsys_modem_snapshot_cdma, data->com_data)); + g_test_suite_add (suite, TESTCASE (test_com_wcdma_subsys_state_info, data->com_data)); + g_test_suite_add (suite, TESTCASE (test_com_gsm_subsys_state_info, data->com_data)); } result = g_test_run (); diff --git a/m4/compiler_warnings.m4 b/m4/compiler_warnings.m4 index 6cea2f7..223da2d 100644 --- a/m4/compiler_warnings.m4 +++ b/m4/compiler_warnings.m4 @@ -10,7 +10,7 @@ if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then for option in -Wshadow -Wmissing-declarations -Wmissing-prototypes \ -Wdeclaration-after-statement -Wstrict-prototypes \ -Wfloat-equal -Wno-unused-parameter -Wno-sign-compare \ - -fno-strict-aliasing; do + -fno-strict-aliasing -Wno-deprecated-declarations; do SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $option" AC_MSG_CHECKING([whether gcc understands $option]) diff --git a/m4/nls.m4 b/m4/nls.m4 new file mode 100644 index 0000000..7967cc2 --- /dev/null +++ b/m4/nls.m4 @@ -0,0 +1,31 @@ +# nls.m4 serial 3 (gettext-0.15) +dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2003. + +AC_PREREQ(2.50) + +AC_DEFUN([AM_NLS], +[ + AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) +]) diff --git a/marshallers/Makefile.in b/marshallers/Makefile.in index bec116d..b04d471 100644 --- a/marshallers/Makefile.in +++ b/marshallers/Makefile.in @@ -41,7 +41,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/plugins/77-mm-ericsson-mbm.rules b/plugins/77-mm-ericsson-mbm.rules index 8c03acf..897bd5c 100644 --- a/plugins/77-mm-ericsson-mbm.rules +++ b/plugins/77-mm-ericsson-mbm.rules @@ -30,6 +30,27 @@ ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190b", ENV{ID_MM_ERICSSON_MBM}="1" ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190d", ENV{ID_MM_ERICSSON_MBM}="1" ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1911", ENV{ID_MM_ERICSSON_MBM}="1" +# Ericsson H5321gw +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1919", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson H5321w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191d", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson F5321gw +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1917", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson F5321w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191b", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson C5621gw +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191f", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson C5621w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1921", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson C3304w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1928", ENV{ID_MM_ERICSSON_MBM}="1" + # Sony-Ericsson MD300 ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0cf", ENV{ID_MM_ERICSSON_MBM}="1" @@ -39,6 +60,9 @@ ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0e1", ENV{ID_MM_ERICSSON_MBM}="1" # Sony-Ericsson MD400G ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d103", ENV{ID_MM_ERICSSON_MBM}="1" +# Dell 5560 +ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818e", ENV{ID_MM_ERICSSON_MBM}="1" + # Dell 5550 ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818d", ENV{ID_MM_ERICSSON_MBM}="1" @@ -59,6 +83,9 @@ ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="271d", ENV{ID_MM_ERICSSON_MBM}="1" # HP hs2320 Mobile Broadband Module ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="261d", ENV{ID_MM_ERICSSON_MBM}="1" +# HP hs2340 Mobile Broadband Module +ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="3a1d", ENV{ID_MM_ERICSSON_MBM}="1" + # HP lc2000 Mobile Broadband Module ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="301d", ENV{ID_MM_ERICSSON_MBM}="1" diff --git a/plugins/77-mm-nokia-port-types.rules b/plugins/77-mm-nokia-port-types.rules new file mode 100644 index 0000000..560f3ce --- /dev/null +++ b/plugins/77-mm-nokia-port-types.rules @@ -0,0 +1,39 @@ +# do not edit this file, it will be overwritten on update + +ACTION!="add|change", GOTO="mm_nokia_port_types_end" +SUBSYSTEM!="tty", GOTO="mm_nokia_port_types_end" + +SUBSYSTEMS=="usb", ATTRS{idVendor}=="0421", GOTO="mm_nokia_port_types_vendorcheck" +GOTO="mm_nokia_port_types_end" + +LABEL="mm_nokia_port_types_vendorcheck" +SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" + +# For Nokia Internet Sticks (CS-xx) the modem/PPP port appears to always be USB interface 1 + +ATTRS{idProduct}=="060D", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0611", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="061A", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="061B", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="061F", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0620", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0623", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0624", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0625", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="062A", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="062E", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="062F", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +LABEL="mm_nokia_port_types_end" + diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 47fc3b0..2b71246 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -189,6 +189,9 @@ libmm_plugin_sierra_la_LDFLAGS = \ -module \ -avoid-version +libmm_plugin_sierra_la_LIBADD = \ + $(builddir)/libicera-utils.la + # Wavecom (Sierra Airlink) libmm_plugin_wavecom_la_SOURCES = \ @@ -384,7 +387,8 @@ udevrules_DATA = \ 77-mm-zte-port-types.rules \ 77-mm-longcheer-port-types.rules \ 77-mm-simtech-port-types.rules \ - 77-mm-x22x-port-types.rules + 77-mm-x22x-port-types.rules \ + 77-mm-nokia-port-types.rules BUILT_SOURCES = \ mm-modem-gsm-hso-glue.h diff --git a/plugins/Makefile.in b/plugins/Makefile.in index df6b5e3..b2dea3f 100644 --- a/plugins/Makefile.in +++ b/plugins/Makefile.in @@ -46,7 +46,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -204,7 +204,7 @@ libmm_plugin_samsung_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libmm_plugin_samsung_la_LDFLAGS) \ $(LDFLAGS) -o $@ -libmm_plugin_sierra_la_LIBADD = +libmm_plugin_sierra_la_DEPENDENCIES = $(builddir)/libicera-utils.la am_libmm_plugin_sierra_la_OBJECTS = \ libmm_plugin_sierra_la-mm-plugin-sierra.lo \ libmm_plugin_sierra_la-mm-modem-sierra-gsm.lo \ @@ -648,6 +648,9 @@ libmm_plugin_sierra_la_LDFLAGS = \ -module \ -avoid-version +libmm_plugin_sierra_la_LIBADD = \ + $(builddir)/libicera-utils.la + # Wavecom (Sierra Airlink) libmm_plugin_wavecom_la_SOURCES = \ @@ -843,7 +846,8 @@ udevrules_DATA = \ 77-mm-zte-port-types.rules \ 77-mm-longcheer-port-types.rules \ 77-mm-simtech-port-types.rules \ - 77-mm-x22x-port-types.rules + 77-mm-x22x-port-types.rules \ + 77-mm-nokia-port-types.rules BUILT_SOURCES = \ mm-modem-gsm-hso-glue.h diff --git a/plugins/mm-modem-anydata-cdma.c b/plugins/mm-modem-anydata-cdma.c index 7b6b37a..d26d3ec 100644 --- a/plugins/mm-modem-anydata-cdma.c +++ b/plugins/mm-modem-anydata-cdma.c @@ -183,6 +183,9 @@ evdo_state_done (MMAtSerialPort *port, } } + g_match_info_free (match_info); + g_regex_unref (r); + done: mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state); mm_callback_info_schedule (info); @@ -254,6 +257,9 @@ state_done (MMAtSerialPort *port, } } + g_match_info_free (match_info); + g_regex_unref (r); + mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state); /* Try for EVDO state too */ diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c index e3d4dce..5d4201c 100644 --- a/plugins/mm-modem-hso.c +++ b/plugins/mm-modem-hso.c @@ -778,7 +778,12 @@ grab_port (MMModem *modem, goto out; if (MM_IS_AT_SERIAL_PORT (port)) { - g_object_set (G_OBJECT (port), MM_SERIAL_PORT_SEND_DELAY, (guint64) 0, NULL); + g_object_set (G_OBJECT (port), + MM_SERIAL_PORT_SEND_DELAY, (guint64) 0, + /* built-in echo removal conflicts with unsolicited _OWANCALL + * messages, which are not prefixed. */ + MM_AT_SERIAL_PORT_REMOVE_ECHO, FALSE, + NULL); if (ptype == MM_PORT_TYPE_PRIMARY) { GRegex *regex; @@ -854,4 +859,3 @@ mm_modem_hso_class_init (MMModemHsoClass *klass) gsm_class->get_allowed_mode = get_allowed_mode; gsm_class->get_access_technology = get_access_technology; } - diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c index 5f4c2fb..4fc3c3f 100644 --- a/plugins/mm-modem-huawei-gsm.c +++ b/plugins/mm-modem-huawei-gsm.c @@ -599,9 +599,9 @@ send_huawei_cpin_done (MMAtSerialPort *port, mm_callback_info_set_result (info, GUINT_TO_POINTER (attempts_left), NULL); - g_match_info_free (match_info); - done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_serial_port_close (MM_SERIAL_PORT (port)); @@ -729,82 +729,6 @@ handle_status_change (MMAtSerialPort *port, /*****************************************************************************/ -static void -do_enable_power_up_done (MMGenericGsm *gsm, - GString *response, - GError *error, - MMCallbackInfo *info) -{ - if (!error) { - MMAtSerialPort *primary; - - /* Enable unsolicited result codes */ - primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY); - g_assert (primary); - - mm_at_serial_port_queue_command (primary, "^CURC=1", 5, NULL, NULL); - } - - /* Chain up to parent */ - MM_GENERIC_GSM_CLASS (mm_modem_huawei_gsm_parent_class)->do_enable_power_up_done (gsm, NULL, error, info); -} - -/*****************************************************************************/ - -static void -disable_unsolicited_done (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data) - -{ - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - - /* If the modem has already been removed, return without - * scheduling callback */ - if (mm_callback_info_check_modem_removed (info)) - return; - - /* Ignore all errors */ - mm_callback_info_schedule (info); -} - -static void -invoke_call_parent_disable_fn (MMCallbackInfo *info) -{ - /* Note: we won't call the parent disable if info->modem is no longer - * valid. The invoke is called always once the info gets scheduled, which - * may happen during removed modem detection. */ - if (info->modem) { - MMModem *parent_modem_iface; - - parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem)); - parent_modem_iface->disable (info->modem, (MMModemFn)info->callback, info->user_data); - } -} - -static void -disable (MMModem *modem, - MMModemFn callback, - gpointer user_data) -{ - MMAtSerialPort *primary; - MMCallbackInfo *info; - - info = mm_callback_info_new_full (modem, - invoke_call_parent_disable_fn, - (GCallback)callback, - user_data); - - primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); - g_assert (primary); - - /* Turn off unsolicited responses */ - mm_at_serial_port_queue_command (primary, "^CURC=0", 5, disable_unsolicited_done, info); -} - -/*****************************************************************************/ - static gboolean grab_port (MMModem *modem, const char *subsys, @@ -888,6 +812,16 @@ ussd_encode (MMModemGsmUssd *self, const char* command, guint *scheme) *scheme = MM_MODEM_GSM_USSD_SCHEME_7BIT; gsm = mm_charset_utf8_to_unpacked_gsm (command, &len); + + /* If command is a multiple of 7 characters long, Huawei firmwares + * apparently want that padded. Maybe all modems? + */ + if (len % 7 == 0) { + gsm = g_realloc (gsm, len + 1); + gsm[len] = 0x0d; + len++; + } + packed = gsm_pack (gsm, len, 0, &packed_len); hex = utils_bin2hexstr (packed, packed_len); g_free (packed); @@ -906,8 +840,11 @@ ussd_decode (MMModemGsmUssd *self, const char* reply, guint scheme) guint32 unpacked_len; bin = utils_hexstr2bin (reply, &bin_len); - unpacked = gsm_unpack ((guint8*)bin, bin_len, 0, &unpacked_len); - utf8 = (char*)mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len); + unpacked = gsm_unpack ((guint8*) bin, (bin_len * 8) / 7, 0, &unpacked_len); + /* if the last character in a 7-byte block is padding, then drop it */ + if ((bin_len % 7 == 0) && (unpacked[unpacked_len - 1] == 0x0d)) + unpacked_len--; + utf8 = (char*) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len); g_free (bin); g_free (unpacked); @@ -920,7 +857,6 @@ static void modem_init (MMModem *modem_class) { modem_class->grab_port = grab_port; - modem_class->disable = disable; } static void @@ -960,6 +896,5 @@ mm_modem_huawei_gsm_class_init (MMModemHuaweiGsmClass *klass) gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; gsm_class->get_access_technology = get_access_technology; - gsm_class->do_enable_power_up_done = do_enable_power_up_done; } diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c index 7aa8a01..ab39ff6 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -730,7 +730,9 @@ enap_poll_response (MMAtSerialPort *port, count = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mbm-enap-poll-count")); - if (sscanf (response->str, "*ENAP: %d", &state) == 1 && state == 1) { + if ( response + && sscanf (response->str, "*ENAP: %d", &state) == 1 + && state == 1) { /* Success! Connected... */ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info); return; diff --git a/plugins/mm-modem-nokia.c b/plugins/mm-modem-nokia.c index 56f4c1b..9476f61 100644 --- a/plugins/mm-modem-nokia.c +++ b/plugins/mm-modem-nokia.c @@ -120,6 +120,11 @@ get_property (GObject *object, guint prop_id, case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD: g_value_set_string (value, ""); break; + case MM_GENERIC_GSM_PROP_INIT_CMD: + /* When initializing a Nokia phone, first enable the echo, + * and then disable it, so that we get it properly disabled */ + g_value_set_string (value, "Z E1 E0 V1"); + break; default: break; } @@ -135,6 +140,10 @@ mm_modem_nokia_class_init (MMModemNokiaClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; + g_object_class_override_property (object_class, + MM_GENERIC_GSM_PROP_INIT_CMD, + MM_GENERIC_GSM_INIT_CMD); + g_object_class_override_property (object_class, MM_GENERIC_GSM_PROP_POWER_UP_CMD, MM_GENERIC_GSM_POWER_UP_CMD); diff --git a/plugins/mm-modem-novatel-cdma.c b/plugins/mm-modem-novatel-cdma.c index c1f4151..77d6bee 100644 --- a/plugins/mm-modem-novatel-cdma.c +++ b/plugins/mm-modem-novatel-cdma.c @@ -181,7 +181,7 @@ get_signal_quality (MMModemCdma *modem, /*****************************************************************************/ static void -parse_modem_snapshot (MMCallbackInfo *info, QCDMResult *result) +parse_modem_snapshot (MMCallbackInfo *info, QcdmResult *result) { MMModemCdmaRegistrationState evdo_state, cdma1x_state, new_state; guint8 eri = 0; @@ -193,7 +193,7 @@ parse_modem_snapshot (MMCallbackInfo *info, QCDMResult *result) cdma1x_state = mm_generic_cdma_query_reg_state_get_callback_1x_state (info); /* Roaming? */ - if (qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &eri)) { + if (qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &eri)) { char *str; gboolean roaming = FALSE; @@ -216,7 +216,7 @@ reg_nwsnap_6500_cb (MMQcdmSerialPort *port, gpointer user_data) { MMCallbackInfo *info = user_data; - QCDMResult *result; + QcdmResult *result; if (!error) { result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, NULL); @@ -235,20 +235,18 @@ reg_nwsnap_6800_cb (MMQcdmSerialPort *port, gpointer user_data) { MMCallbackInfo *info = user_data; - QCDMResult *result; + QcdmResult *result; GByteArray *nwsnap; if (error) goto done; /* Parse the response */ - result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, &info->error); + result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, NULL); if (!result) { - g_clear_error (&info->error); - /* Try for MSM6500 */ nwsnap = g_byte_array_sized_new (25); - nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6500, NULL); + nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6500); g_assert (nwsnap->len); mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6500_cb, info); return; @@ -282,7 +280,7 @@ query_registration_state (MMGenericCdma *cdma, /* Try MSM6800 first since newer cards use that */ nwsnap = g_byte_array_sized_new (25); - nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6800, NULL); + nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6800); g_assert (nwsnap->len); mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6800_cb, info); } diff --git a/plugins/mm-modem-novatel-gsm.c b/plugins/mm-modem-novatel-gsm.c index 5d78db7..706664c 100644 --- a/plugins/mm-modem-novatel-gsm.c +++ b/plugins/mm-modem-novatel-gsm.c @@ -198,8 +198,6 @@ parse_nwrat_response (GString *response, mode = atoi (str); g_free (str); - g_match_info_free (match_info); - if (mode < 0 || mode > 2) { g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Failed to parse mode/tech response"); @@ -219,6 +217,7 @@ parse_nwrat_response (GString *response, success = TRUE; out: + g_match_info_free (match_info); g_regex_unref (r); return success; } diff --git a/plugins/mm-modem-samsung-gsm.c b/plugins/mm-modem-samsung-gsm.c index f2d339b..05cebe4 100755 --- a/plugins/mm-modem-samsung-gsm.c +++ b/plugins/mm-modem-samsung-gsm.c @@ -357,9 +357,9 @@ send_samsung_pinnum_done (MMAtSerialPort *port, mm_callback_info_set_result (info, GUINT_TO_POINTER (attempts_left), NULL); - g_match_info_free (match_info); - done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_serial_port_close (MM_SERIAL_PORT (port)); diff --git a/plugins/mm-modem-sierra-gsm.c b/plugins/mm-modem-sierra-gsm.c index 551142e..1a9b735 100644 --- a/plugins/mm-modem-sierra-gsm.c +++ b/plugins/mm-modem-sierra-gsm.c @@ -25,12 +25,16 @@ #include "mm-modem-simple.h" #include "mm-callback-info.h" #include "mm-modem-helpers.h" +#include "mm-log.h" +#include "mm-modem-icera.h" static void modem_init (MMModem *modem_class); +static void modem_icera_init (MMModemIcera *icera_class); static void modem_simple_init (MMModemSimple *class); G_DEFINE_TYPE_EXTENDED (MMModemSierraGsm, mm_modem_sierra_gsm, MM_TYPE_GENERIC_GSM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_ICERA, modem_icera_init) G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init)) #define MM_MODEM_SIERRA_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_SIERRA_GSM, MMModemSierraGsmPrivate)) @@ -40,6 +44,8 @@ typedef struct { gboolean has_net; char *username; char *password; + gboolean is_icera; + MMModemIceraPrivate *icera; } MMModemSierraGsmPrivate; MMModem * @@ -49,17 +55,23 @@ mm_modem_sierra_gsm_new (const char *device, guint32 vendor, guint32 product) { + MMModem *modem; + g_return_val_if_fail (device != NULL, NULL); g_return_val_if_fail (driver != NULL, NULL); g_return_val_if_fail (plugin != NULL, NULL); - return MM_MODEM (g_object_new (MM_TYPE_MODEM_SIERRA_GSM, - MM_MODEM_MASTER_DEVICE, device, - MM_MODEM_DRIVER, driver, - MM_MODEM_PLUGIN, plugin, - MM_MODEM_HW_VID, vendor, - MM_MODEM_HW_PID, product, - NULL)); + modem = (MMModem *) g_object_new (MM_TYPE_MODEM_SIERRA_GSM, + MM_MODEM_MASTER_DEVICE, device, + MM_MODEM_DRIVER, driver, + MM_MODEM_PLUGIN, plugin, + MM_MODEM_HW_VID, vendor, + MM_MODEM_HW_PID, product, + NULL); + if (modem) + MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem)->icera = mm_modem_icera_init_private (); + + return modem; } /*****************************************************************************/ @@ -72,7 +84,7 @@ get_allowed_mode_done (MMAtSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; GRegex *r = NULL; - GMatchInfo *match_info; + GMatchInfo *match_info = NULL; /* If the modem has already been removed, return without * scheduling callback */ @@ -127,6 +139,8 @@ get_allowed_mode_done (MMAtSerialPort *port, } done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_callback_info_schedule (info); @@ -137,9 +151,15 @@ get_allowed_mode (MMGenericGsm *gsm, MMModemUIntFn callback, gpointer user_data) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (gsm); MMCallbackInfo *info; MMAtSerialPort *primary; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_get_allowed_mode (MM_MODEM_ICERA (self), callback, user_data); + return; + } + info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data); /* Sierra secondary ports don't have full AT command interpreters */ @@ -179,11 +199,17 @@ set_allowed_mode (MMGenericGsm *gsm, MMModemFn callback, gpointer user_data) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (gsm); MMCallbackInfo *info; MMAtSerialPort *primary; char *command; int idx = 0; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_set_allowed_mode (MM_MODEM_ICERA (self), mode, callback, user_data); + return; + } + info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data); /* Sierra secondary ports don't have full AT command interpreters */ @@ -251,9 +277,15 @@ get_access_technology (MMGenericGsm *modem, MMModemUIntFn callback, gpointer user_data) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (modem); MMAtSerialPort *port; MMCallbackInfo *info; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_get_access_technology (MM_MODEM_ICERA (self), callback, user_data); + return; + } + info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); port = mm_generic_gsm_get_best_at_port (modem, &info->error); @@ -353,6 +385,28 @@ error: /* Modem class override functions */ /*****************************************************************************/ +static void +icera_check_cb (MMModem *modem, + guint32 result, + GError *error, + gpointer user_data) +{ + if (!error) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (user_data); + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (self); + + if (result) { + priv->is_icera = TRUE; + g_object_set (G_OBJECT (modem), + MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_STATIC, + NULL); + + /* Turn on unsolicited network state messages */ + mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (modem), TRUE); + } + } +} + static gboolean sierra_enabled (gpointer user_data) { @@ -365,6 +419,8 @@ sierra_enabled (gpointer user_data) modem = MM_GENERIC_GSM (info->modem); priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem); priv->enable_wait_id = 0; + mm_modem_icera_is_icera (MM_MODEM_ICERA (modem), icera_check_cb, MM_MODEM_SIERRA_GSM (modem)); + MM_GENERIC_GSM_CLASS (mm_modem_sierra_gsm_parent_class)->do_enable_power_up_done (modem, NULL, NULL, info); } return FALSE; @@ -391,6 +447,64 @@ real_do_enable_power_up_done (MMGenericGsm *gsm, priv->enable_wait_id = g_timeout_add_seconds (10, sierra_enabled, info); } +static void +get_current_functionality_status_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + guint needed = FALSE; + + /* If the modem has already been removed, return without + * scheduling callback */ + if (mm_callback_info_check_modem_removed (info)) + return; + + /* On error, just assume we don't need the power-up command */ + if (!error) { + const gchar *p; + + p = mm_strip_tag (response->str, "+CFUN:"); + if (p && *p == '1') { + /* If reported functionality status is '1', then we do not need to + * issue the power-up command. Otherwise, do it. */ + mm_dbg ("Already in full functionality status, skipping power-up command"); + } else { + needed = TRUE; + mm_warn ("Not in full functionality status, power-up command is needed."); + } + } else + mm_warn ("Failed checking if power-up command is needed: '%s'. " + "Will assume it isn't.", + error->message); + + /* Set result and schedule */ + mm_callback_info_set_result (info, + GUINT_TO_POINTER (needed), + NULL); + mm_callback_info_schedule (info); +} + +static void +do_enable_power_up_check_needed (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *primary; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + /* Get port */ + primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + /* Get current functionality status */ + mm_dbg ("Getting current functionality status..."); + mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info); +} + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -422,6 +536,9 @@ grab_port (MMModem *modem, regex = g_regex_new ("\\r\\n\\+PACSP0\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL); g_regex_unref (regex); + + /* Add Icera-specific handlers */ + mm_modem_icera_register_unsolicted_handlers (MM_MODEM_ICERA (gsm), MM_AT_SERIAL_PORT (port)); } else if (mm_port_get_subsys (port) == MM_PORT_SUBSYS_NET) { MM_MODEM_SIERRA_GSM_GET_PRIVATE (gsm)->has_net = TRUE; g_object_set (G_OBJECT (gsm), MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_DHCP, NULL); @@ -554,6 +671,11 @@ do_connect (MMModem *modem, MMCallbackInfo *info; MMAtSerialPort *port; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem)->is_icera) { + mm_modem_icera_do_connect (MM_MODEM_ICERA (modem), number, callback, user_data); + return; + } + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); info = mm_callback_info_new (modem, callback, user_data); @@ -572,6 +694,21 @@ do_connect (MMModem *modem, mm_at_serial_port_queue_command (port, "+CGATT=1", 10, ps_attach_done, info); } +static void +get_ip4_config (MMModem *modem, + MMModemIp4Fn callback, + gpointer user_data) +{ + MMModem *parent_iface; + + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem)->is_icera) { + mm_modem_icera_get_ip4_config (MM_MODEM_ICERA (modem), callback, user_data); + } else { + parent_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); + parent_iface->get_ip4_config (modem, callback, user_data); + } +} + static void clear_user_pass (MMModemSierraGsm *self) { @@ -589,9 +726,17 @@ do_disconnect (MMGenericGsm *gsm, MMModemFn callback, gpointer user_data) { - clear_user_pass (MM_MODEM_SIERRA_GSM (gsm)); + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (gsm); + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (self); - if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (gsm)->has_net) { + if (priv->is_icera) { + mm_modem_icera_do_disconnect (gsm, cid, callback, user_data); + return; + } + + clear_user_pass (self); + + if (priv->has_net) { MMAtSerialPort *primary; char *command; @@ -607,6 +752,68 @@ do_disconnect (MMGenericGsm *gsm, MM_GENERIC_GSM_CLASS (mm_modem_sierra_gsm_parent_class)->do_disconnect (gsm, cid, callback, user_data); } + +/*****************************************************************************/ + +static void +disable_unsolicited_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) + +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + /* If the modem has already been removed, return without + * scheduling callback */ + if (mm_callback_info_check_modem_removed (info)) + return; + + /* Ignore all errors */ + mm_callback_info_schedule (info); +} + +static void +invoke_call_parent_disable_fn (MMCallbackInfo *info) +{ + /* Note: we won't call the parent disable if info->modem is no longer + * valid. The invoke is called always once the info gets scheduled, which + * may happen during removed modem detection. */ + if (info->modem) { + MMModem *parent_modem_iface; + + parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem)); + parent_modem_iface->disable (info->modem, (MMModemFn)info->callback, info->user_data); + } +} + +static void +do_disable (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem); + MMAtSerialPort *primary; + MMCallbackInfo *info; + + info = mm_callback_info_new_full (modem, + invoke_call_parent_disable_fn, + (GCallback)callback, + user_data); + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + /* Turn off unsolicited responses */ + if (priv->is_icera) { + mm_modem_icera_cleanup (MM_MODEM_ICERA (modem)); + mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (modem), FALSE); + } + + /* Random command to ensure unsolicited message disable completes */ + mm_at_serial_port_queue_command (primary, "E0", 5, disable_unsolicited_done, info); +} + /*****************************************************************************/ /* Simple Modem class override functions */ /*****************************************************************************/ @@ -640,9 +847,13 @@ simple_connect (MMModemSimple *simple, MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMModemSimple *parent_iface; - clear_user_pass (MM_MODEM_SIERRA_GSM (simple)); - priv->username = simple_dup_string_property (properties, "username", &info->error); - priv->password = simple_dup_string_property (properties, "password", &info->error); + if (priv->is_icera) { + mm_modem_icera_simple_connect (MM_MODEM_ICERA (simple), properties); + } else { + clear_user_pass (MM_MODEM_SIERRA_GSM (simple)); + priv->username = simple_dup_string_property (properties, "username", &info->error); + priv->password = simple_dup_string_property (properties, "password", &info->error); + } parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple)); parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info); @@ -650,11 +861,27 @@ simple_connect (MMModemSimple *simple, /*****************************************************************************/ +static MMModemIceraPrivate * +get_icera_private (MMModemIcera *icera) +{ + return MM_MODEM_SIERRA_GSM_GET_PRIVATE (icera)->icera; +} + +/*****************************************************************************/ + static void modem_init (MMModem *modem_class) { modem_class->grab_port = grab_port; modem_class->connect = do_connect; + modem_class->disable = do_disable; + modem_class->get_ip4_config = get_ip4_config; +} + +static void +modem_icera_init (MMModemIcera *icera) +{ + icera->get_private = get_icera_private; } static void @@ -671,12 +898,15 @@ mm_modem_sierra_gsm_init (MMModemSierraGsm *self) static void dispose (GObject *object) { - MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (object); + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (object); + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (self); if (priv->enable_wait_id) g_source_remove (priv->enable_wait_id); - clear_user_pass (MM_MODEM_SIERRA_GSM (object)); + mm_modem_icera_dispose_private (MM_MODEM_ICERA (self)); + + clear_user_pass (self); } static void @@ -689,6 +919,7 @@ mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass) g_type_class_add_private (object_class, sizeof (MMModemSierraGsmPrivate)); object_class->dispose = dispose; + gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed; gsm_class->do_enable_power_up_done = real_do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; diff --git a/plugins/mm-modem-wavecom-gsm.c b/plugins/mm-modem-wavecom-gsm.c index c66637c..3bfcdbe 100644 --- a/plugins/mm-modem-wavecom-gsm.c +++ b/plugins/mm-modem-wavecom-gsm.c @@ -218,15 +218,20 @@ get_property (GObject *object, { switch (prop_id) { case MM_GENERIC_GSM_PROP_POWER_UP_CMD: - /* Wavecom doesn't like CFUN=1, it will reset the whole software stack, - * including the USB connection and therefore connection would get - * closed */ - g_value_set_string (value, ""); + /* Try to go to full functionality mode without rebooting the system. + * Works well if we previously switched off the power with CFUN=4 + */ + g_value_set_string (value, "+CFUN=1,0"); break; case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD: /* Wavecom doesn't have XOFF/XON flow control, so we enable RTS/CTS */ g_value_set_string (value, "+IFC=2,2"); break; + case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD: + /* Use AT+CFUN=4 for power down. It will stop the RF (IMSI detach), and + * keeps access to the SIM */ + g_value_set_string (value, "+CFUN=4"); + break; default: break; } @@ -869,7 +874,7 @@ set_highest_ms_class_cb (MMAtSerialPort *port, } /* All done without errors! */ - mm_dbg ("[5/5] All done"); + mm_dbg ("[4/4] All done"); enable_complete (MM_GENERIC_GSM (info->modem), NULL, info); } @@ -975,7 +980,7 @@ get_current_ms_class_cb (MMAtSerialPort *port, } /* Next, set highest mobile station class possible */ - mm_dbg ("[4/5] Ensuring highest MS class..."); + mm_dbg ("[3/4] Ensuring highest MS class..."); set_highest_ms_class (port, info); } @@ -1039,19 +1044,18 @@ get_supported_ms_classes_cb (MMAtSerialPort *port, } /* Next, query for current MS class */ - mm_dbg ("[3/5] Getting current MS class..."); + mm_dbg ("[2/4] Getting current MS class..."); mm_at_serial_port_queue_command (port, "+CGCLASS?", 3, get_current_ms_class_cb, info); } static void -get_current_functionality_status_cb (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data) +do_enable_power_up_done (MMGenericGsm *gsm, + GString *response, + GError *error, + MMCallbackInfo *info) { - MMCallbackInfo *info = user_data; - const gchar *p; - GError *inner_error; + MMAtSerialPort *port; + GError *inner_error = NULL; /* If the modem has already been removed, return without * scheduling callback */ @@ -1059,57 +1063,79 @@ get_current_functionality_status_cb (MMAtSerialPort *port, return; if (error) { - enable_complete (MM_GENERIC_GSM (info->modem), error, info); + enable_complete (gsm, error, info); return; } - p = mm_strip_tag (response->str, "+CFUN:"); - if (!p || *p != '1') { - /* Reported functionality status MUST be '1'. Otherwise, RF is probably - * switched off. */ - inner_error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "Unexpected functionality status: '%c'. ", - p ? *p :' '); - enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info); + /* Get port */ + port = mm_generic_gsm_get_best_at_port (gsm, &inner_error); + if (!port) { + enable_complete (gsm, inner_error, info); g_error_free (inner_error); + return; } - /* Nex, query for supported MS classes */ - mm_dbg ("[2/5] Getting supported MS classes..."); + mm_dbg ("[1/4] Getting supported MS classes..."); mm_at_serial_port_queue_command (port, "+CGCLASS=?", 3, get_supported_ms_classes_cb, info); } static void -do_enable_power_up_done (MMGenericGsm *gsm, - GString *response, - GError *error, - MMCallbackInfo *info) +get_current_functionality_status_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) { - MMAtSerialPort *port; - GError *inner_error = NULL; + MMCallbackInfo *info = user_data; + guint needed = FALSE; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; - if (error) { - enable_complete (gsm, error, info); - return; - } + /* On error, just assume we don't need the power-up command */ + if (!error) { + const gchar *p; + + p = mm_strip_tag (response->str, "+CFUN:"); + if (p && *p == '1') { + /* If reported functionality status is '1', then we do not need to + * issue the power-up command. Otherwise, do it. */ + mm_dbg ("Already in full functionality status, skipping power-up command"); + } else { + needed = TRUE; + mm_warn ("Not in full functionality status, power-up command is needed. " + "Note that it may reboot the modem."); + } + } else + mm_warn ("Failed checking if power-up command is needed: '%s'. " + "Will assume it isn't.", + error->message); + + /* Set result and schedule */ + mm_callback_info_set_result (info, + GUINT_TO_POINTER (needed), + NULL); + mm_callback_info_schedule (info); +} + +static void +do_enable_power_up_check_needed (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *primary; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); /* Get port */ - port = mm_generic_gsm_get_best_at_port (gsm, &inner_error); - if (!port) { - enable_complete (gsm, inner_error, info); - g_error_free (inner_error); - return; - } + primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY); + g_assert (primary); - /* Next, get current functionality status */ - mm_dbg ("[1/5] Getting current functionality status..."); - mm_at_serial_port_queue_command (port, "+CFUN?", 3, get_current_functionality_status_cb, info); + /* Get current functionality status */ + mm_dbg ("Getting current functionality status..."); + mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info); } /*****************************************************************************/ @@ -1158,6 +1184,11 @@ mm_modem_wavecom_gsm_class_init (MMModemWavecomGsmClass *klass) MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD, MM_GENERIC_GSM_FLOW_CONTROL_CMD); + g_object_class_override_property (object_class, + MM_GENERIC_GSM_PROP_POWER_DOWN_CMD, + MM_GENERIC_GSM_POWER_DOWN_CMD); + + gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed; gsm_class->do_enable_power_up_done = do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; diff --git a/plugins/mm-modem-x22x-gsm.c b/plugins/mm-modem-x22x-gsm.c index 012733d..a31cd36 100644 --- a/plugins/mm-modem-x22x-gsm.c +++ b/plugins/mm-modem-x22x-gsm.c @@ -81,8 +81,6 @@ parse_syssel_response (GString *response, mode = atoi (str); g_free (str); - g_match_info_free (match_info); - if (mode < 0 || mode > 2) { g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Failed to parse mode/tech response"); @@ -102,6 +100,7 @@ parse_syssel_response (GString *response, success = TRUE; out: + g_match_info_free (match_info); g_regex_unref (r); return success; } diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c index 6c9f395..88ef734 100644 --- a/plugins/mm-modem-zte.c +++ b/plugins/mm-modem-zte.c @@ -105,7 +105,7 @@ get_allowed_mode_done (MMAtSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; GRegex *r = NULL; - GMatchInfo *match_info; + GMatchInfo *match_info = NULL; /* If the modem has already been removed, return without * scheduling callback */ @@ -138,8 +138,6 @@ get_allowed_mode_done (MMAtSerialPort *port, pref_acq = atoi (str); g_free (str); - g_match_info_free (match_info); - if (cm_mode < 0 || cm_mode > 2 || pref_acq < 0 || pref_acq > 2) { info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, @@ -164,6 +162,8 @@ get_allowed_mode_done (MMAtSerialPort *port, } done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_callback_info_schedule (info); diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c index aef3c52..fe7ffa0 100644 --- a/plugins/mm-plugin-huawei.c +++ b/plugins/mm-plugin-huawei.c @@ -15,7 +15,6 @@ */ #include -#include #include #define G_UDEV_API_IS_SUBJECT_TO_CHANGE @@ -29,7 +28,6 @@ #include "mm-serial-parsers.h" #include "mm-at-serial-port.h" #include "mm-log.h" -#include "mm-errors.h" G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE) @@ -46,8 +44,6 @@ mm_plugin_create (void) /*****************************************************************************/ -#define TAG_HUAWEI_PCUI_PORT "huawei-pcui-port" - #define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \ MM_PLUGIN_BASE_PORT_CAP_IS856 | \ @@ -74,59 +70,95 @@ probe_result (MMPluginBase *base, mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities)); } +#define TAG_SUPPORTS_INFO "huawei-supports-info" + +typedef struct { + MMAtSerialPort *serial; + guint id; + MMPortType ptype; + /* Whether or not there's already a detected modem that "owns" this port, + * in which case we'll claim it, but if no capabilities are detected it'll + * just be ignored. + */ + gboolean parent_modem; +} HuaweiSupportsInfo; + +static void +huawei_supports_info_destroy (gpointer user_data) +{ + HuaweiSupportsInfo *info = user_data; + + if (info->id) + g_source_remove (info->id); + if (info->serial) + g_object_unref (info->serial); + memset (info, 0, sizeof (HuaweiSupportsInfo)); + g_free (info); +} + static gboolean -getportmode_response_cb (MMPluginBaseSupportsTask *task, - GString *response, - GError *error, - guint32 tries, - gboolean *out_stop, - guint32 *out_level, - gpointer user_data) +probe_secondary_supported (gpointer user_data) { - /* If any error occurred that was not ERROR or COMMAND NOT SUPPORT then - * retry the command. - */ - if (error) { - if (g_error_matches (error, MM_MOBILE_ERROR, MM_MOBILE_ERROR_UNKNOWN) == FALSE) - return tries <= 4 ? TRUE : FALSE; - } else { - MMPlugin *plugin; - char *p; - int i = 0; - - /* Get the USB interface number of the PCUI port */ - p = strstr (response->str, "PCUI:"); - if (p) - i = atoi (p + strlen ("PCUI:")); - - if (i) { - /* Save they PCUI port number for later */ - plugin = mm_plugin_base_supports_task_get_plugin (task); - g_assert (plugin); - g_object_set_data (G_OBJECT (plugin), TAG_HUAWEI_PCUI_PORT, GINT_TO_POINTER (i)); - } - } + MMPluginBaseSupportsTask *task = user_data; + HuaweiSupportsInfo *info; + + info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO); - /* No error or if ^GETPORTMODE is not supported, assume success */ + info->id = 0; + g_object_unref (info->serial); + info->serial = NULL; + + /* Yay, supported, we got an unsolicited message */ + info->ptype = MM_PORT_TYPE_SECONDARY; + mm_plugin_base_supports_task_complete (task, 10); return FALSE; } +static void +probe_secondary_handle_msg (MMAtSerialPort *port, + GMatchInfo *match_info, + gpointer user_data) +{ + MMPluginBaseSupportsTask *task = user_data; + HuaweiSupportsInfo *info; + + info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO); + g_source_remove (info->id); + info->id = g_idle_add (probe_secondary_supported, task); +} + static gboolean -curc_response_cb (MMPluginBaseSupportsTask *task, - GString *response, - GError *error, - guint32 tries, - gboolean *out_stop, - guint32 *out_level, - gpointer user_data) +probe_secondary_timeout (gpointer user_data) { - if (error) - return tries <= 4 ? TRUE : FALSE; + MMPluginBaseSupportsTask *task = user_data; + HuaweiSupportsInfo *info; + guint level = 0; + + info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO); + info->id = 0; + g_object_unref (info->serial); + info->serial = NULL; + + /* Supported, but ignored if this port's parent device is already a modem */ + if (info->parent_modem) { + info->ptype = MM_PORT_TYPE_IGNORED; + level = 10; + } - /* No error, assume success */ + mm_plugin_base_supports_task_complete (task, level); return FALSE; } +static void +add_regex (MMAtSerialPort *port, const char *match, gpointer user_data) +{ + GRegex *regex; + + regex = g_regex_new (match, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (port, regex, probe_secondary_handle_msg, user_data, NULL); + g_regex_unref (regex); +} + static MMPluginSupportsResult supports_port (MMPluginBase *base, MMModem *existing, @@ -134,9 +166,10 @@ supports_port (MMPluginBase *base, { GUdevDevice *port; guint32 cached = 0, level; - const char *subsys, *name; + const char *subsys, *name, *driver; int usbif; guint16 vendor = 0, product = 0; + guint32 existing_type = MM_MODEM_TYPE_UNKNOWN; /* Can't do anything with non-serial ports */ port = mm_plugin_base_supports_task_get_port (task); @@ -152,52 +185,81 @@ supports_port (MMPluginBase *base, if (vendor != 0x12d1) return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + /* The Gobi driver should claim Huawei Gobi modems */ + driver = mm_plugin_base_supports_task_get_driver (task); + if (g_strcmp0 (driver, "qcserial") == 0) + return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM"); if (usbif < 0) return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; - /* The primary port (called the "modem" port in the Windows drivers) is - * always USB interface 0, and we need to detect that interface first for - * two reasons: (1) to disable unsolicited messages on other ports that - * may fill up the buffer and crash the device, and (2) to attempt to get - * the port layout for hints about what the secondary port is (called the - * "pcui" port in Windows). Thus we probe USB interface 0 first and defer - * probing other interfaces until we've got if0, at which point we allow - * the other ports to be probed too. + /* The secondary ports don't necessarily respond correctly to probing, so + * we need to use the first port that does respond to probing to create the + * right type of mode (GSM or CDMA), and then re-check the other interfaces. */ if (!existing && usbif != 0) return MM_PLUGIN_SUPPORTS_PORT_DEFER; - if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) { - level = get_level_for_capabilities (cached); - if (level) { - mm_plugin_base_supports_task_complete (task, level); + /* CDMA devices don't have problems with the secondary ports, so after + * ensuring we have a device by probing the first port, probe the secondary + * ports on CDMA devices too. + */ + if (existing) + g_object_get (G_OBJECT (existing), MM_MODEM_TYPE, &existing_type, NULL); + + if (usbif == 0 || (existing_type == MM_MODEM_TYPE_CDMA)) { + if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) { + level = get_level_for_capabilities (cached); + if (level) { + mm_plugin_base_supports_task_complete (task, level); + return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; + } + return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + } + + /* Otherwise kick off a probe */ + if (mm_plugin_base_probe_port (base, task, 100000, NULL)) return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; + } else { + HuaweiSupportsInfo *info; + GError *error = NULL; + + /* Listen for Huawei-specific unsolicited messages */ + info = g_malloc0 (sizeof (HuaweiSupportsInfo)); + info->parent_modem = !!existing; + + info->serial = mm_at_serial_port_new (name, MM_PORT_TYPE_PRIMARY); + g_object_set (G_OBJECT (info->serial), MM_PORT_CARRIER_DETECT, FALSE, NULL); + + mm_at_serial_port_set_response_parser (info->serial, + mm_serial_parser_v1_parse, + mm_serial_parser_v1_new (), + mm_serial_parser_v1_destroy); + + add_regex (info->serial, "\\r\\n\\^RSSI:(\\d+)\\r\\n", task); + add_regex (info->serial, "\\r\\n\\^MODE:(\\d),(\\d)\\r\\n", task); + add_regex (info->serial, "\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", task); + add_regex (info->serial, "\\r\\n\\^BOOT:.+\\r\\n", task); + add_regex (info->serial, "\\r\\r\\^BOOT:.+\\r\\r", task); + + info->id = g_timeout_add_seconds (7, probe_secondary_timeout, task); + + if (!mm_serial_port_open (MM_SERIAL_PORT (info->serial), &error)) { + mm_warn ("(Huawei) %s: couldn't open serial port: (%d) %s", + name, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + huawei_supports_info_destroy (info); + return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; } - return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; - } - /* Turn off unsolicited messages on secondary ports until needed, - * and try to get a port map from the modem. The response will - * get handled in custom_init_response(). - */ - if (usbif == 0) { - mm_plugin_base_supports_task_add_custom_init_command (task, - "AT^CURC=0", - 3, /* delay */ - curc_response_cb, - NULL); - - mm_plugin_base_supports_task_add_custom_init_command (task, - "AT^GETPORTMODE", - 3, /* delay */ - getportmode_response_cb, - NULL); - } + g_object_set_data_full (G_OBJECT (task), TAG_SUPPORTS_INFO, + info, huawei_supports_info_destroy); - /* Kick off a probe */ - if (mm_plugin_base_probe_port (base, task, 100000, NULL)) return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; + } return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; } @@ -257,21 +319,12 @@ grab_port (MMPluginBase *base, } } } else { + HuaweiSupportsInfo *info; MMPortType ptype = MM_PORT_TYPE_UNKNOWN; - int pcui_usbif, port_usbif; - - /* Any additional AT ports can be secondary ports, but we want to ensure - * that the "pcui" port found from ^GETPORTMODE above is always set as - * a secondary port too. - */ - - port_usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM"); - pcui_usbif = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (base), TAG_HUAWEI_PCUI_PORT)); - if ( (port_usbif == pcui_usbif) - || (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) - || (caps & CAP_CDMA)) - ptype = MM_PORT_TYPE_SECONDARY; + info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO); + if (info) + ptype = info->ptype; else if (caps & MM_PLUGIN_BASE_PORT_CAP_QCDM) ptype = MM_PORT_TYPE_QCDM; diff --git a/plugins/mm-plugin-longcheer.c b/plugins/mm-plugin-longcheer.c index 5f773a3..89a6138 100644 --- a/plugins/mm-plugin-longcheer.c +++ b/plugins/mm-plugin-longcheer.c @@ -72,12 +72,13 @@ custom_init_response_cb (MMPluginBaseSupportsTask *task, guint32 *out_level, gpointer user_data) { - const char *p = response->str; + const char *p; if (error) return tries <= 4 ? TRUE : FALSE; /* Note the lack of a ':' on the GMR; the X200 doesn't send one */ + g_assert (response); p = mm_strip_tag (response->str, "AT+GMR"); if (*p == 'L') { /* X200 modems have a GMR firmware revision that starts with 'L', and diff --git a/plugins/mm-plugin-nokia.c b/plugins/mm-plugin-nokia.c index 28e9022..de05c2d 100644 --- a/plugins/mm-plugin-nokia.c +++ b/plugins/mm-plugin-nokia.c @@ -59,6 +59,22 @@ probe_result (MMPluginBase *base, mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities)); } +static gboolean +custom_init_response_cb (MMPluginBaseSupportsTask *task, + GString *response, + GError *error, + guint32 tries, + gboolean *out_stop, + guint32 *out_level, + gpointer user_data) +{ + if (error) + return tries <= 4 ? TRUE : FALSE; + + /* No error, assume success */ + return FALSE; +} + static MMPluginSupportsResult supports_port (MMPluginBase *base, MMModem *existing, @@ -92,6 +108,12 @@ supports_port (MMPluginBase *base, return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; } + mm_plugin_base_supports_task_add_custom_init_command (task, + "ATE1 E0", + 3, + custom_init_response_cb, + NULL); + /* Otherwise kick off a probe */ if (mm_plugin_base_probe_port (base, task, 100000, NULL)) return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; @@ -110,6 +132,7 @@ grab_port (MMPluginBase *base, const char *name, *subsys, *devfile, *sysfs_path; guint32 caps; guint16 vendor = 0, product = 0; + MMPortType ptype = MM_PORT_TYPE_UNKNOWN; port = mm_plugin_base_supports_task_get_port (task); g_assert (port); @@ -128,6 +151,12 @@ grab_port (MMPluginBase *base, return NULL; } + /* Look for port type hints */ + if (g_udev_device_get_property_as_boolean (port, "ID_MM_NOKIA_PORT_TYPE_MODEM")) + ptype = MM_PORT_TYPE_PRIMARY; + else if (g_udev_device_get_property_as_boolean (port, "ID_MM_NOKIA_PORT_TYPE_AUX")) + ptype = MM_PORT_TYPE_SECONDARY; + caps = mm_plugin_base_supports_task_get_probed_capabilities (task); sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task); if (!existing) { @@ -148,14 +177,14 @@ grab_port (MMPluginBase *base, } if (modem) { - if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) { + if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error)) { g_object_unref (modem); return NULL; } } } else if (get_level_for_capabilities (caps)) { modem = existing; - if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) + if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error)) return NULL; } diff --git a/plugins/mm-plugin-x22x.c b/plugins/mm-plugin-x22x.c index 3be6731..a76a919 100644 --- a/plugins/mm-plugin-x22x.c +++ b/plugins/mm-plugin-x22x.c @@ -70,12 +70,13 @@ custom_init_response_cb (MMPluginBaseSupportsTask *task, guint32 *out_level, gpointer user_data) { - const char *p = response->str; + const char *p; if (error) return tries <= 4 ? TRUE : FALSE; /* Note the lack of a ':' on the GMR; the X200 doesn't send one */ + g_assert (response); p = mm_strip_tag (response->str, "AT+GMR"); if (*p != 'L') { /* X200 modems have a GMR firmware revision that starts with 'L', and diff --git a/policy/Makefile.in b/policy/Makefile.in index 8824e7d..0156280 100644 --- a/policy/Makefile.in +++ b/policy/Makefile.in @@ -42,7 +42,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/policy/org.freedesktop.modem-manager.policy b/policy/org.freedesktop.modem-manager.policy index 97228cd..2b9af3f 100644 --- a/policy/org.freedesktop.modem-manager.policy +++ b/policy/org.freedesktop.modem-manager.policy @@ -28,7 +28,7 @@ Add, modify, and delete mobile broadband contacts - System policy prevents adding, modifying, or deleteing this device's contacts. + System policy prevents adding, modifying, or deleting this device's contacts. no auth_self_keep diff --git a/policy/org.freedesktop.modem-manager.policy.in b/policy/org.freedesktop.modem-manager.policy.in index 3790918..23f7834 100644 --- a/policy/org.freedesktop.modem-manager.policy.in +++ b/policy/org.freedesktop.modem-manager.policy.in @@ -29,7 +29,7 @@ <_description>Add, modify, and delete mobile broadband contacts - <_message>System policy prevents adding, modifying, or deleteing this device's contacts. + <_message>System policy prevents adding, modifying, or deleting this device's contacts. no auth_self_keep diff --git a/src/Makefile.in b/src/Makefile.in index 1f2f622..d559bc2 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -52,7 +52,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/src/mm-at-serial-port.c b/src/mm-at-serial-port.c index 30da3a3..5bc1789 100644 --- a/src/mm-at-serial-port.c +++ b/src/mm-at-serial-port.c @@ -29,14 +29,21 @@ G_DEFINE_TYPE (MMAtSerialPort, mm_at_serial_port, MM_TYPE_SERIAL_PORT) #define MM_AT_SERIAL_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_AT_SERIAL_PORT, MMAtSerialPortPrivate)) +enum { + PROP_0, + PROP_REMOVE_ECHO, + LAST_PROP +}; + typedef struct { /* Response parser data */ MMAtSerialResponseParserFn response_parser_fn; gpointer response_parser_user_data; GDestroyNotify response_parser_notify; GSList *unsolicited_msg_handlers; -} MMAtSerialPortPrivate; + gboolean remove_echo; +} MMAtSerialPortPrivate; /*****************************************************************************/ @@ -58,6 +65,26 @@ mm_at_serial_port_set_response_parser (MMAtSerialPort *self, priv->response_parser_notify = notify; } +void +mm_at_serial_port_remove_echo (GByteArray *response) +{ + guint i; + + if (response->len <= 2) + return; + + for (i = 0; i < (response->len - 1); i++) { + /* If there is any content before the first + * , assume it's echo or garbage, and skip it */ + if (response->data[i] == '\r' && response->data[i + 1] == '\n') { + if (i > 0) + g_byte_array_remove_range (response, 0, i); + /* else, good, we're already started with */ + break; + } + } +} + static gboolean parse_response (MMSerialPort *port, GByteArray *response, GError **error) { @@ -68,6 +95,10 @@ parse_response (MMSerialPort *port, GByteArray *response, GError **error) g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE); + /* Remove echo */ + if (priv->remove_echo) + mm_at_serial_port_remove_echo (response); + /* Construct the string that AT-parsing functions expect */ string = g_string_sized_new (response->len + 1); g_string_append_len (string, (const char *) response->data, response->len); @@ -159,6 +190,10 @@ parse_unsolicited (MMSerialPort *port, GByteArray *response) MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (self); GSList *iter; + /* Remove echo */ + if (priv->remove_echo) + mm_at_serial_port_remove_echo (response); + for (iter = priv->unsolicited_msg_handlers; iter; iter = iter->next) { MMAtUnsolicitedMsgHandler *handler = (MMAtUnsolicitedMsgHandler *) iter->data; GMatchInfo *match_info; @@ -314,6 +349,42 @@ mm_at_serial_port_new (const char *name, MMPortType ptype) static void mm_at_serial_port_init (MMAtSerialPort *self) { + MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (self); + + /* By default, remove echo */ + priv->remove_echo = TRUE; +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_REMOVE_ECHO: + priv->remove_echo = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_REMOVE_ECHO: + g_value_set_boolean (value, priv->remove_echo); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -349,10 +420,20 @@ mm_at_serial_port_class_init (MMAtSerialPortClass *klass) g_type_class_add_private (object_class, sizeof (MMAtSerialPortPrivate)); /* Virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; object_class->finalize = finalize; port_class->parse_unsolicited = parse_unsolicited; port_class->parse_response = parse_response; port_class->handle_response = handle_response; port_class->debug_log = debug_log; + + g_object_class_install_property + (object_class, PROP_REMOVE_ECHO, + g_param_spec_boolean (MM_AT_SERIAL_PORT_REMOVE_ECHO, + "Remove echo", + "Built-in echo removal should be applied", + TRUE, + G_PARAM_READWRITE)); } diff --git a/src/mm-at-serial-port.h b/src/mm-at-serial-port.h index 5d5f13f..3079470 100644 --- a/src/mm-at-serial-port.h +++ b/src/mm-at-serial-port.h @@ -18,7 +18,6 @@ #define MM_AT_SERIAL_PORT_H #include -#include #include #include "mm-serial-port.h" @@ -46,6 +45,8 @@ typedef void (*MMAtSerialResponseFn) (MMAtSerialPort *port, GError *error, gpointer user_data); +#define MM_AT_SERIAL_PORT_REMOVE_ECHO "remove-echo" + struct _MMAtSerialPort { MMSerialPort parent; }; @@ -81,5 +82,7 @@ void mm_at_serial_port_queue_command_cached (MMAtSerialPort *self, MMAtSerialResponseFn callback, gpointer user_data); -#endif /* MM_AT_SERIAL_PORT_H */ +/* Just for unit tests */ +void mm_at_serial_port_remove_echo (GByteArray *response); +#endif /* MM_AT_SERIAL_PORT_H */ diff --git a/src/mm-charsets.c b/src/mm-charsets.c index cbdf388..832a06f 100644 --- a/src/mm-charsets.c +++ b/src/mm-charsets.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "mm-charsets.h" #include "mm-utils.h" @@ -36,8 +37,8 @@ static CharsetEntry charset_map[] = { { "IRA", "ASCII", "ASCII", "ASCII//TRANSLIT", MM_MODEM_CHARSET_IRA }, { "GSM", NULL, NULL, NULL, MM_MODEM_CHARSET_GSM }, { "8859-1", NULL, "ISO8859-1", "ISO8859-1//TRANSLIT", MM_MODEM_CHARSET_8859_1 }, - { "PCCP437", NULL, NULL, NULL, MM_MODEM_CHARSET_PCCP437 }, - { "PCDN", NULL, NULL, NULL, MM_MODEM_CHARSET_PCDN }, + { "PCCP437", "CP437", "CP437", "CP437//TRANSLIT", MM_MODEM_CHARSET_PCCP437 }, + { "PCDN", "CP850", "CP850", "CP850//TRANSLIT", MM_MODEM_CHARSET_PCDN }, { "HEX", NULL, NULL, NULL, MM_MODEM_CHARSET_HEX }, { NULL, NULL, NULL, NULL, MM_MODEM_CHARSET_UNKNOWN } }; @@ -160,7 +161,8 @@ mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset) g_return_val_if_fail (iconv_from != NULL, FALSE); unconverted = utils_hexstr2bin (src, &unconverted_len); - g_return_val_if_fail (unconverted != NULL, NULL); + if (!unconverted) + return NULL; if (charset == MM_MODEM_CHARSET_UTF8 || charset == MM_MODEM_CHARSET_IRA) return unconverted; @@ -425,6 +427,180 @@ mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len) return g_byte_array_free (gsm, FALSE); } +static gboolean +gsm_is_subset (gunichar c, const char *utf8, gsize ulen, guint *out_clen) +{ + guint8 gsm; + + *out_clen = 1; + if (utf8_to_gsm_def_char (utf8, ulen, &gsm)) + return TRUE; + if (utf8_to_gsm_ext_char (utf8, ulen, &gsm)) { + *out_clen = 2; + return TRUE; + } + return FALSE; +} + +static gboolean +ira_is_subset (gunichar c, const char *utf8, gsize ulen, guint *out_clen) +{ + *out_clen = 1; + return (ulen == 1); +} + +static gboolean +ucs2_is_subset (gunichar c, const char *utf8, gsize ulen, guint *out_clen) +{ + *out_clen = 2; + return (c <= 0xFFFF); +} + +static gboolean +iso88591_is_subset (gunichar c, const char *utf8, gsize ulen, guint *out_clen) +{ + *out_clen = 1; + return (c <= 0xFF); +} + +static gboolean +pccp437_is_subset (gunichar c, const char *utf8, gsize ulen, guint *out_clen) +{ + static const gunichar t[] = { + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, + 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, + 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, + 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, + 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, + 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, + 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, + 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, + 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, + 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, + 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, + 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, + 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, + 0x25a0, 0x00a0 + }; + int i; + + *out_clen = 1; + + if (c <= 0x7F) + return TRUE; + for (i = 0; i < sizeof (t) / sizeof (t[0]); i++) { + if (c == t[i]) + return TRUE; + } + return FALSE; +} + +static gboolean +pcdn_is_subset (gunichar c, const char *utf8, gsize ulen, guint *out_clen) +{ + static const gunichar t[] = { + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, + 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, + 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, + 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, + 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, + 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, + 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, + 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x00f0, + 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce, 0x00cf, 0x2518, + 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x00d3, 0x00df, 0x00d4, + 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe, 0x00de, 0x00da, 0x00db, 0x00d9, + 0x00fd, 0x00dd, 0x00af, 0x00b4, 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, + 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, + 0x25a0, 0x00a0 + }; + int i; + + *out_clen = 1; + + if (c <= 0x7F) + return TRUE; + for (i = 0; i < sizeof (t) / sizeof (t[0]); i++) { + if (c == t[i]) + return TRUE; + } + return FALSE; +} + +typedef struct { + MMModemCharset cs; + gboolean (*func) (gunichar c, const char *utf8, gsize ulen, guint *out_clen); + guint charsize; +} SubsetEntry; + +SubsetEntry subset_table[] = { + { MM_MODEM_CHARSET_GSM, gsm_is_subset }, + { MM_MODEM_CHARSET_IRA, ira_is_subset }, + { MM_MODEM_CHARSET_UCS2, ucs2_is_subset }, + { MM_MODEM_CHARSET_8859_1, iso88591_is_subset }, + { MM_MODEM_CHARSET_PCCP437, pccp437_is_subset }, + { MM_MODEM_CHARSET_PCDN, pcdn_is_subset }, + { MM_MODEM_CHARSET_UNKNOWN, NULL }, +}; + +/** + * mm_charset_get_encoded_len: + * + * @utf8: UTF-8 valid string + * @charset: the #MMModemCharset to check the length of @utf8 in + * @out_unsupported: on return, number of characters of @utf8 that are not fully + * representable in @charset + * + * Returns: the size in bytes of the string if converted from UTF-8 into @charset. + **/ +guint +mm_charset_get_encoded_len (const char *utf8, + MMModemCharset charset, + guint *out_unsupported) +{ + const char *p = utf8, *next; + guint len = 0, unsupported = 0; + SubsetEntry *e; + + g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, 0); + g_return_val_if_fail (utf8 != NULL, 0); + + if (charset == MM_MODEM_CHARSET_UTF8) + return strlen (utf8); + + /* Find the charset in our subset table */ + for (e = &subset_table[0]; + e->cs != charset && e->cs != MM_MODEM_CHARSET_UNKNOWN; + e++); + g_return_val_if_fail (e->cs != MM_MODEM_CHARSET_UNKNOWN, 0); + + while (*p) { + gunichar c; + const char *end; + guint clen = 0; + + c = g_utf8_get_char_validated (p, -1); + g_return_val_if_fail (c != (gunichar) -1, 0); + end = next = g_utf8_find_next_char (p, NULL); + if (end == NULL) { + /* Find the end... */ + end = p; + while (*end++); + } + + if (!e->func (c, p, (end - p), &clen)) + unsupported++; + len += clen; + p = next; + } + + if (out_unsupported) + *out_unsupported = unsupported; + return len; +} + guint8 * gsm_unpack (const guint8 *gsm, guint32 num_septets, @@ -467,37 +643,127 @@ gsm_pack (const guint8 *src, guint8 start_offset, guint32 *out_packed_len) { - GByteArray *packed; - guint8 c, add_last = 0; - int i; + guint8 *packed; + guint octet = 0, lshift, plen; + int i = 0; - packed = g_byte_array_sized_new (src_len); + g_return_val_if_fail (start_offset < 8, NULL); - for (i = 0, c = 0; i < src_len; i++) { - guint8 bits_here, offset; - guint32 start_bit; + plen = (src_len * 7) + start_offset; /* total length in bits */ + if (plen % 8) + plen += 8; + plen /= 8; /* now in bytes */ - start_bit = start_offset + (i * 7); /* Overall bit offset of char in buffer */ - offset = start_bit % 8; /* Offset to start of char in this byte */ - bits_here = offset ? (8 - offset) : 7; + packed = g_malloc0 (plen); - c |= (src[i] & 0x7F) << offset; - if (offset) { - /* Add this packed byte */ - g_byte_array_append (packed, &c, 1); - c = add_last = 0; + for (i = 0, lshift = start_offset; i < src_len; i++) { + packed[octet] |= (src[i] & 0x7F) << lshift; + if (lshift > 1) { + /* Grab the lost bits and add to next octet */ + g_assert (octet + 1 < plen); + packed[octet + 1] = (src[i] & 0x7F) >> (8 - lshift); } + if (lshift) + octet++; + lshift = lshift ? lshift - 1 : 7; + } - /* Pack the rest of this char into the next byte */ - if (bits_here != 7) { - c = (src[i] & 0x7F) >> bits_here; - add_last = 1; + if (out_packed_len) + *out_packed_len = plen; + return packed; +} + +/* We do all our best to get the given string, which is possibly given in the + * specified charset, to UTF8. It may happen that the given string is really + * the hex representation of the charset-encoded string, so we need to cope with + * that case. */ +gchar * +mm_charset_take_and_convert_to_utf8 (gchar *str, + MMModemCharset charset) +{ + gchar *utf8 = NULL; + + if (!str) + return NULL; + + switch (charset) { + case MM_MODEM_CHARSET_UNKNOWN: + g_warn_if_reached (); + utf8 = str; + break; + + case MM_MODEM_CHARSET_HEX: + /* We'll assume that the HEX string is really valid ASCII at the end */ + utf8 = str; + break; + + case MM_MODEM_CHARSET_GSM: + case MM_MODEM_CHARSET_8859_1: + case MM_MODEM_CHARSET_PCCP437: + case MM_MODEM_CHARSET_PCDN: { + const gchar *iconv_from; + GError *error = NULL; + + iconv_from = charset_iconv_from (charset); + utf8 = g_convert (str, strlen (str), + "UTF-8//TRANSLIT", iconv_from, + NULL, NULL, &error); + if (!utf8 || error) { + g_clear_error (&error); + utf8 = NULL; } + + g_free (str); + break; } - if (add_last) - g_byte_array_append (packed, &c, 1); - *out_packed_len = packed->len; - return g_byte_array_free (packed, FALSE); -} + case MM_MODEM_CHARSET_UCS2: { + gsize len; + gboolean possibly_hex = TRUE; + /* If the string comes in hex-UCS-2, len needs to be a multiple of 4 */ + len = strlen (str); + if ((len < 4) || ((len % 4) != 0)) + possibly_hex = FALSE; + else { + const gchar *p = str; + + /* All chars in the string must be hex */ + while (*p && possibly_hex) + possibly_hex = isxdigit (*p++); + } + + /* If we get UCS-2, we expect the HEX representation of the string */ + if (possibly_hex) { + utf8 = mm_modem_charset_hex_to_utf8 (str, charset); + if (!utf8) { + /* If we couldn't convert the string as HEX-UCS-2, try to see if + * the string is valid UTF-8 itself. */ + utf8 = str; + } else + g_free (str); + } else + /* If we already know it's not hex, try to use the string as it is */ + utf8 = str; + + break; + } + + /* If the given charset is ASCII or UTF8, we really expect the final string + * already here */ + case MM_MODEM_CHARSET_IRA: + case MM_MODEM_CHARSET_UTF8: + utf8 = str; + break; + } + + /* Validate UTF-8 always before returning. This result will be exposed in DBus + * very likely... */ + if (!g_utf8_validate (utf8, -1, NULL)) { + /* Better return NULL than an invalid UTF-8 string */ + g_free (utf8); + utf8 = NULL; + } + + return utf8; +} diff --git a/src/mm-charsets.h b/src/mm-charsets.h index 50b0cce..ff701e5 100644 --- a/src/mm-charsets.h +++ b/src/mm-charsets.h @@ -52,6 +52,11 @@ guint8 *mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len); guint8 *mm_charset_gsm_unpacked_to_utf8 (const guint8 *gsm, guint32 len); +/* Returns the size in bytes required to hold the UTF-8 string in the given charset */ +guint mm_charset_get_encoded_len (const char *utf8, + MMModemCharset charset, + guint *out_unsupported); + guint8 *gsm_unpack (const guint8 *gsm, guint32 num_septets, guint8 start_offset, /* in bits */ @@ -62,5 +67,7 @@ guint8 *gsm_pack (const guint8 *src, guint8 start_offset, /* in bits */ guint32 *out_packed_len); -#endif /* MM_CHARSETS_H */ +gchar *mm_charset_take_and_convert_to_utf8 (gchar *str, + MMModemCharset charset); +#endif /* MM_CHARSETS_H */ diff --git a/src/mm-errors.c b/src/mm-errors.c index e4fdda7..841ad0f 100644 --- a/src/mm-errors.c +++ b/src/mm-errors.c @@ -353,3 +353,144 @@ mm_mobile_error_for_string (const char *str) return g_error_new_literal (MM_MOBILE_ERROR, error_code, msg); } +/********************************************************************/ + +GQuark +mm_msg_error_quark (void) +{ + static GQuark ret = 0; + + if (ret == 0) + ret = g_quark_from_static_string ("mm_msg_error"); + + return ret; +} + +GType +mm_msg_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + ENUM_ENTRY (MM_MSG_ERROR_ME_FAILURE, "MeFailure"), + ENUM_ENTRY (MM_MSG_ERROR_SMS_SERVICE_RESERVED, "SmsServiceReserved"), + ENUM_ENTRY (MM_MSG_ERROR_NOT_ALLOWED, "OperationNotAllowed"), + ENUM_ENTRY (MM_MSG_ERROR_NOT_SUPPORTED, "OperationNotSupported"), + ENUM_ENTRY (MM_MSG_ERROR_INVALID_PDU_PARAMETER, "InvalidPduParameter"), + ENUM_ENTRY (MM_MSG_ERROR_INVALID_TEXT_PARAMETER, "InvalidTextParameter"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_NOT_INSERTED, "SimNotInserted"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_PIN, "SimPinRequired"), + ENUM_ENTRY (MM_MSG_ERROR_PH_SIM_PIN, "PhSimPinRequired"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_FAILURE, "SimFailure"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_BUSY, "SimBusy"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_WRONG, "SimWrong"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_PUK, "SimPukRequired"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_PIN2, "SimPin2Required"), + ENUM_ENTRY (MM_MSG_ERROR_SIM_PUK2, "SimPuk2Required"), + ENUM_ENTRY (MM_MSG_ERROR_MEMORY_FAILURE, "MemoryFailure"), + ENUM_ENTRY (MM_MSG_ERROR_INVALID_INDEX, "InvalidIndex"), + ENUM_ENTRY (MM_MSG_ERROR_MEMORY_FULL, "MemoryFull"), + ENUM_ENTRY (MM_MSG_ERROR_SMSC_ADDRESS_UNKNOWN, "SmscAddressUnknown"), + ENUM_ENTRY (MM_MSG_ERROR_NO_NETWORK, "NoNetwork"), + ENUM_ENTRY (MM_MSG_ERROR_NETWORK_TIMEOUT, "NetworkTimeout"), + ENUM_ENTRY (MM_MSG_ERROR_NO_CNMA_ACK_EXPECTED, "NoCnmaAckExpected"), + ENUM_ENTRY (MM_MSG_ERROR_UNKNOWN, "Unknown"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("MMMsgError", values); + } + + return etype; +} + +static ErrorTable msg_errors[] = { + { MM_MSG_ERROR_ME_FAILURE, "mefailure", "ME failure" }, + { MM_MSG_ERROR_SMS_SERVICE_RESERVED, "smsservicereserved", "SMS service reserved" }, + { MM_MSG_ERROR_NOT_ALLOWED, "operationnotallowed", "Operation not allowed" }, + { MM_MSG_ERROR_NOT_SUPPORTED, "operationnotsupported", "Operation not supported" }, + { MM_MSG_ERROR_INVALID_PDU_PARAMETER, "invalidpduparameter", "Invalid PDU mode parameter" }, + { MM_MSG_ERROR_INVALID_TEXT_PARAMETER, "invalidtextparameter", "Invalid text mode parameter" }, + { MM_MSG_ERROR_SIM_NOT_INSERTED, "simnotinserted", "SIM not inserted" }, + { MM_MSG_ERROR_SIM_PIN, "simpinrequired", "SIM PIN required" }, + { MM_MSG_ERROR_PH_SIM_PIN, "phsimpinrequired", "PH-SIM PIN required" }, + { MM_MSG_ERROR_SIM_FAILURE, "simfailure", "SIM failure" }, + { MM_MSG_ERROR_SIM_BUSY, "simbusy", "SIM busy" }, + { MM_MSG_ERROR_SIM_WRONG, "simwrong", "SIM wrong" }, + { MM_MSG_ERROR_SIM_PUK, "simpukrequired", "SIM PUK required" }, + { MM_MSG_ERROR_SIM_PIN2, "simpin2required", "SIM PIN2 required" }, + { MM_MSG_ERROR_SIM_PUK2, "simpuk2required", "SIM PUK2 required" }, + { MM_MSG_ERROR_MEMORY_FAILURE, "memoryfailure", "Memory failure" }, + { MM_MSG_ERROR_INVALID_INDEX, "invalidindex", "Invalid index" }, + { MM_MSG_ERROR_MEMORY_FULL, "memoryfull", "Memory full" }, + { MM_MSG_ERROR_SMSC_ADDRESS_UNKNOWN, "smscaddressunknown", "SMSC address unknown" }, + { MM_MSG_ERROR_NO_NETWORK, "nonetwork", "No network" }, + { MM_MSG_ERROR_NETWORK_TIMEOUT, "networktimeout", "Network timeout" }, + { MM_MSG_ERROR_NO_CNMA_ACK_EXPECTED, "nocnmaackexpected", "No CNMA acknowledgement expected" }, + { MM_MSG_ERROR_UNKNOWN, "unknown", "Unknown" }, + { -1, NULL, NULL } +}; + +GError * +mm_msg_error_for_code (int error_code) +{ + const char *msg = NULL; + const ErrorTable *ptr = &msg_errors[0]; + + while (ptr->code >= 0) { + if (ptr->code == error_code) { + msg = ptr->message; + break; + } + ptr++; + } + + if (!msg) { + g_warning ("Invalid error code: %d", error_code); + error_code = MM_MSG_ERROR_UNKNOWN; + msg = "Unknown error"; + } + + return g_error_new_literal (MM_MSG_ERROR, error_code, msg); +} + +#define BUF_SIZE 100 + +GError * +mm_msg_error_for_string (const char *str) +{ + int error_code = -1; + const ErrorTable *ptr = &msg_errors[0]; + char buf[BUF_SIZE + 1]; + const char *msg = NULL, *p = str; + int i = 0; + + g_return_val_if_fail (str != NULL, NULL); + + /* Normalize the error code by stripping whitespace and odd characters */ + while (*p && i < BUF_SIZE) { + if (isalnum (*p)) + buf[i++] = tolower (*p); + p++; + } + buf[i] = '\0'; + + while (ptr->code >= 0) { + if (!strcmp (buf, ptr->error)) { + error_code = ptr->code; + msg = ptr->message; + break; + } + ptr++; + } + + if (!msg) { + g_warning ("Invalid error code: %d", error_code); + error_code = MM_MSG_ERROR_UNKNOWN; + msg = "Unknown error"; + } + + return g_error_new_literal (MM_MSG_ERROR, error_code, msg); +} + diff --git a/src/mm-errors.h b/src/mm-errors.h index 13a531d..dd11fdc 100644 --- a/src/mm-errors.h +++ b/src/mm-errors.h @@ -134,4 +134,43 @@ GType mm_mobile_error_get_type (void); GError *mm_mobile_error_for_code (int error_code); GError *mm_mobile_error_for_string (const char *str); + +/* 3GPP TS 27.005 version 10 section 3.2.5 */ +enum { + /* 0 -> 127 per 3GPP TS 24.011 [6] clause E.2 */ + /* 128 -> 255 per 3GPP TS 23.040 [3] clause 9.2.3.22 */ + MM_MSG_ERROR_ME_FAILURE = 300, + MM_MSG_ERROR_SMS_SERVICE_RESERVED = 301, + MM_MSG_ERROR_NOT_ALLOWED = 302, + MM_MSG_ERROR_NOT_SUPPORTED = 303, + MM_MSG_ERROR_INVALID_PDU_PARAMETER = 304, + MM_MSG_ERROR_INVALID_TEXT_PARAMETER = 305, + MM_MSG_ERROR_SIM_NOT_INSERTED = 310, + MM_MSG_ERROR_SIM_PIN = 311, + MM_MSG_ERROR_PH_SIM_PIN = 312, + MM_MSG_ERROR_SIM_FAILURE = 313, + MM_MSG_ERROR_SIM_BUSY = 314, + MM_MSG_ERROR_SIM_WRONG = 315, + MM_MSG_ERROR_SIM_PUK = 316, + MM_MSG_ERROR_SIM_PIN2 = 317, + MM_MSG_ERROR_SIM_PUK2 = 318, + MM_MSG_ERROR_MEMORY_FAILURE = 320, + MM_MSG_ERROR_INVALID_INDEX = 321, + MM_MSG_ERROR_MEMORY_FULL = 322, + MM_MSG_ERROR_SMSC_ADDRESS_UNKNOWN = 330, + MM_MSG_ERROR_NO_NETWORK = 331, + MM_MSG_ERROR_NETWORK_TIMEOUT = 332, + MM_MSG_ERROR_NO_CNMA_ACK_EXPECTED = 340, + MM_MSG_ERROR_UNKNOWN = 500, +}; + + +#define MM_MSG_ERROR (mm_msg_error_quark ()) +#define MM_TYPE_MSG_ERROR (mm_msg_error_get_type ()) + +GQuark mm_msg_error_quark (void); +GType mm_msg_error_get_type (void); +GError *mm_msg_error_for_code (int error_code); +GError *mm_msg_error_for_string (const char *str); + #endif /* MM_MODEM_ERROR_H */ diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index 11987a2..515cfdd 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -30,6 +30,7 @@ #include "mm-serial-parsers.h" #include "mm-modem-helpers.h" #include "libqcdm/src/commands.h" +#include "libqcdm/src/errors.h" #include "mm-log.h" #define MM_GENERIC_CDMA_PREV_STATE_TAG "prev-state" @@ -988,7 +989,6 @@ get_signal_quality_done (MMAtSerialPort *port, { MMGenericCdmaPrivate *priv; MMCallbackInfo *info = (MMCallbackInfo *) user_data; - char *reply = response->str; /* If the modem has already been removed, return without * scheduling callback */ @@ -1008,6 +1008,7 @@ get_signal_quality_done (MMAtSerialPort *port, return; } } else { + const char *reply = response->str; int quality, ber; /* Got valid reply */ @@ -1047,9 +1048,10 @@ qcdm_pilot_sets_cb (MMQcdmSerialPort *port, { MMCallbackInfo *info = user_data; MMGenericCdmaPrivate *priv; - QCDMResult *result; + QcdmResult *result; guint32 num = 0, quality = 0, i; float best_db = -28; + int err = QCDM_SUCCESS; if (error) { info->error = g_error_copy (error); @@ -1059,9 +1061,12 @@ qcdm_pilot_sets_cb (MMQcdmSerialPort *port, priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); /* Parse the response */ - result = qcdm_cmd_pilot_sets_result ((const char *) response->data, response->len, &info->error); - if (!result) + result = qcdm_cmd_pilot_sets_result ((const char *) response->data, response->len, &err); + if (!result) { + g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Failed to parse pilot sets command result: %d", err); goto done; + } qcdm_cmd_pilot_sets_result_get_num (result, QCDM_CMD_PILOT_SETS_TYPE_ACTIVE, &num); for (i = 0; i < num; i++) { @@ -1128,7 +1133,7 @@ get_signal_quality (MMModemCdma *modem, /* Use CDMA1x pilot EC/IO if we can */ pilot_sets = g_byte_array_sized_new (25); - pilot_sets->len = qcdm_cmd_pilot_sets_new ((char *) pilot_sets->data, 25, NULL); + pilot_sets->len = qcdm_cmd_pilot_sets_new ((char *) pilot_sets->data, 25); g_assert (pilot_sets->len); mm_qcdm_serial_port_queue_command (priv->qcdm, pilot_sets, 3, qcdm_pilot_sets_cb, info); } @@ -1273,7 +1278,7 @@ serving_system_done (MMAtSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - char *reply = response->str; + char *reply; int class = 0, sid = 99999, num; unsigned char band = 'Z'; gboolean success = FALSE; @@ -1288,6 +1293,7 @@ serving_system_done (MMAtSerialPort *port, goto out; } + reply = response->str; if (strstr (reply, "+CSS: ")) reply += 6; @@ -1399,19 +1405,23 @@ cdma_status_cb (MMQcdmSerialPort *port, gpointer user_data) { MMCallbackInfo *info = user_data; - QCDMResult *result; + QcdmResult *result; guint32 sid, rxstate; + int err = QCDM_SUCCESS; if (error) goto error; /* Parse the response */ - result = qcdm_cmd_cdma_status_result ((const char *) response->data, response->len, &info->error); - if (!result) + result = qcdm_cmd_cdma_status_result ((const char *) response->data, response->len, &err); + if (!result) { + g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Failed to parse cdma status command result: %d", err); goto error; + } - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RX_STATE, &rxstate); - qcdm_result_get_uint32 (result, QCDM_CMD_CDMA_STATUS_ITEM_SID, &sid); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RX_STATE, &rxstate); + qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_SID, &sid); qcdm_result_unref (result); if (rxstate == QCDM_CMD_CDMA_STATUS_RX_STATE_ENTERING_CDMA) @@ -1448,7 +1458,7 @@ get_serving_system (MMModemCdma *modem, GByteArray *cdma_status; cdma_status = g_byte_array_sized_new (25); - cdma_status->len = qcdm_cmd_cdma_status_new ((char *) cdma_status->data, 25, NULL); + cdma_status->len = qcdm_cmd_cdma_status_new ((char *) cdma_status->data, 25); g_assert (cdma_status->len); mm_qcdm_serial_port_queue_command (priv->qcdm, cdma_status, 3, cdma_status_cb, info); } else @@ -1826,7 +1836,7 @@ reg_hdrstate_cb (MMQcdmSerialPort *port, gpointer user_data) { MMCallbackInfo *info = user_data; - QCDMResult *result = NULL; + QcdmResult *result = NULL; guint32 sysmode; MMModemCdmaRegistrationState cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; MMModemCdmaRegistrationState evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; @@ -1847,9 +1857,9 @@ reg_hdrstate_cb (MMQcdmSerialPort *port, guint8 almp_state = QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_INACTIVE; guint8 hybrid_mode = 0; - if ( qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, &session_state) - && qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, &almp_state) - && qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, &hybrid_mode)) { + if ( qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, &session_state) + && qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, &almp_state) + && qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, &hybrid_mode)) { /* EVDO state is registered if the HDR subsystem is registered, and * we're in hybrid mode, and the Call Manager system mode is @@ -1918,31 +1928,32 @@ reg_cmstate_cb (MMQcdmSerialPort *port, { MMCallbackInfo *info = user_data; MMAtSerialPort *at_port = NULL; - QCDMResult *result = NULL; + QcdmResult *result = NULL; guint32 opmode = 0, sysmode = 0; - GError *qcdm_error = NULL; + int err = QCDM_SUCCESS; /* Parse the response */ if (!error) - result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &qcdm_error); + result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &err); if (!result) { /* If there was some error, fall back to use +CAD like we did before QCDM */ if (info->modem) at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (info->modem), &info->error); - else - info->error = g_error_copy (qcdm_error); + else { + g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Failed to parse CM subsys state info command result: %d", err); + } if (at_port) mm_at_serial_port_queue_command (at_port, "+CAD?", 3, get_analog_digital_done, info); else mm_callback_info_schedule (info); - g_clear_error (&qcdm_error); return; } - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &opmode); - qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &sysmode); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &opmode); + qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &sysmode); qcdm_result_unref (result); if (opmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE) { @@ -1952,7 +1963,7 @@ reg_cmstate_cb (MMQcdmSerialPort *port, /* Get HDR subsystem state */ hdrstate = g_byte_array_sized_new (25); - hdrstate->len = qcdm_cmd_hdr_subsys_state_info_new ((char *) hdrstate->data, 25, NULL); + hdrstate->len = qcdm_cmd_hdr_subsys_state_info_new ((char *) hdrstate->data, 25); g_assert (hdrstate->len); mm_qcdm_serial_port_queue_command (port, hdrstate, 3, reg_hdrstate_cb, info); } else { @@ -1997,7 +2008,7 @@ get_registration_state (MMModemCdma *modem, GByteArray *cmstate; cmstate = g_byte_array_sized_new (25); - cmstate->len = qcdm_cmd_cm_subsys_state_info_new ((char *) cmstate->data, 25, NULL); + cmstate->len = qcdm_cmd_cm_subsys_state_info_new ((char *) cmstate->data, 25); g_assert (cmstate->len); mm_qcdm_serial_port_queue_command (priv->qcdm, cmstate, 3, reg_cmstate_cb, info); } else @@ -2142,6 +2153,7 @@ simple_reg_callback (MMModemCdma *modem, /* Fail immediately on anything but "no service" */ if (error && !no_service_error) { simple_state_machine (MM_MODEM (modem), error, info); + g_error_free (error); return; } @@ -2300,7 +2312,7 @@ simple_connect (MMModemSimple *simple, MM_MODEM_ERROR_OPERATION_IN_PROGRESS, "Connection is already in progress"); callback (MM_MODEM (simple), error, user_data); - g_error_free (error); + g_clear_error (&error); return; } @@ -2317,6 +2329,7 @@ simple_connect (MMModemSimple *simple, } simple_state_machine (MM_MODEM (simple), error, info); + g_clear_error (&error); } static void diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index cee1bd6..23378b2 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "mm-generic-gsm.h" #include "mm-modem-gsm-card.h" @@ -129,6 +130,17 @@ typedef struct { /* SMS */ GHashTable *sms_present; + /* Map from SMS index numbers to parsed PDUs (themselves as hash tables) */ + GHashTable *sms_contents; + /* + * Map from multipart SMS reference numbers to SMSMultiPartMessage + * structures. + */ + GHashTable *sms_parts; + gboolean sms_pdu_mode; + gboolean sms_pdu_supported; + + guint sms_fetch_pending; } MMGenericGsmPrivate; static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info); @@ -146,11 +158,6 @@ static void reg_state_changed (MMAtSerialPort *port, GMatchInfo *match_info, gpointer user_data); -static void get_reg_status_done (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data); - static gboolean handle_reg_status_response (MMGenericGsm *self, GString *response, GError **error); @@ -334,7 +341,7 @@ pin_check_done (MMAtSerialPort *port, info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Could not parse PIN request response '%s'", - response->str); + response ? response->str : "(unknown)"); } } @@ -1329,6 +1336,242 @@ ciev_received (MMAtSerialPort *port, /* FIXME: handle roaming and service indicators */ } +typedef struct { + /* + * The key index number that refers to this multipart message - + * usually the index number of the first part received. + */ + guint index; + + /* Number of parts in the complete message */ + guint numparts; + + /* Number of parts missing from the message */ + guint missing; + + /* Array of (index numbers of) message parts, in order */ + guint *parts; +} SMSMultiPartMessage; + +static void +sms_cache_insert (MMModem *modem, GHashTable *properties, guint idx) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + GHashTable *old_properties; + GValue *ref; + + ref = g_hash_table_lookup (properties, "concat-reference"); + if (ref != NULL) { + GValue *max, *seq; + guint refnum, maxnum, seqnum; + SMSMultiPartMessage *mpm; + + max = g_hash_table_lookup (properties, "concat-max"); + seq = g_hash_table_lookup (properties, "concat-sequence"); + if (max == NULL || seq == NULL) { + /* Internal error - not all required data present */ + return; + } + + refnum = g_value_get_uint (ref); + maxnum = g_value_get_uint (max); + seqnum = g_value_get_uint (seq); + + if (seqnum > maxnum) { + /* Error - SMS says "part N of M", but N > M */ + return; + } + + mpm = g_hash_table_lookup (priv->sms_parts, GUINT_TO_POINTER (refnum)); + if (mpm == NULL) { + /* Create a new one */ + if (maxnum > 255) + maxnum = 255; + mpm = g_malloc0 (sizeof (*mpm)); + mpm->index = idx; + mpm->numparts = maxnum; + mpm->missing = maxnum; + mpm->parts = g_malloc0 (maxnum * sizeof(*mpm->parts)); + g_hash_table_insert (priv->sms_parts, GUINT_TO_POINTER (refnum), + mpm); + } + + if (maxnum != mpm->numparts) { + /* Error - other messages with this refnum claim a different number of parts */ + return; + } + + if (mpm->parts[seqnum - 1] != 0) { + /* Error - two SMS segments have claimed to be the same part of the same message. */ + return; + } + + mpm->parts[seqnum - 1] = idx; + mpm->missing--; + } + + old_properties = g_hash_table_lookup (priv->sms_contents, GUINT_TO_POINTER (idx)); + if (old_properties != NULL) + g_hash_table_unref (old_properties); + + g_hash_table_insert (priv->sms_contents, GUINT_TO_POINTER (idx), + g_hash_table_ref (properties)); +} + +/* + * Takes a hash table representing a (possibly partial) SMS and + * determines if it is the key part of a complete SMS. The complete + * SMS, if any, is returned. If there is no such SMS (for example, not + * all parts are present yet), NULL is returned. The passed-in hash + * table is dereferenced, and the returned hash table is referenced. + */ +static GHashTable * +sms_cache_lookup_full (MMModem *modem, + GHashTable *properties, + GError **error) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + int i, refnum, indexnum; + SMSMultiPartMessage *mpm; + GHashTable *full, *part, *first; + GHashTableIter iter; + gpointer key, value; + char *fulltext; + char **textparts; + GValue *ref, *idx, *text; + + ref = g_hash_table_lookup (properties, "concat-reference"); + if (ref == NULL) + return properties; + refnum = g_value_get_uint (ref); + + idx = g_hash_table_lookup (properties, "index"); + if (idx == NULL) { + g_hash_table_unref (properties); + return NULL; + } + + indexnum = g_value_get_uint (idx); + g_hash_table_unref (properties); + + mpm = g_hash_table_lookup (priv->sms_parts, + GUINT_TO_POINTER (refnum)); + if (mpm == NULL) { + g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Internal error - no multipart structure for multipart SMS"); + return NULL; + } + + /* Check that this is the key */ + if (indexnum != mpm->index) + return NULL; + + if (mpm->missing != 0) + return NULL; + + /* Complete multipart message is present. Assemble it */ + textparts = g_malloc0((1 + mpm->numparts) * sizeof (*textparts)); + for (i = 0 ; i < mpm->numparts ; i++) { + part = g_hash_table_lookup (priv->sms_contents, + GUINT_TO_POINTER (mpm->parts[i])); + if (part == NULL) { + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Internal error - part %d (index %d) is missing", + i, mpm->parts[i]); + g_free (textparts); + return NULL; + } + text = g_hash_table_lookup (part, "text"); + if (text == NULL) { + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Internal error - part %d (index %d) has no text element", + i, mpm->parts[i]); + g_free (textparts); + return NULL; + } + textparts[i] = g_value_dup_string (text); + } + textparts[i] = NULL; + fulltext = g_strjoinv (NULL, textparts); + g_strfreev (textparts); + + first = g_hash_table_lookup (priv->sms_contents, + GUINT_TO_POINTER (mpm->parts[0])); + full = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + simple_free_gvalue); + g_hash_table_iter_init (&iter, first); + while (g_hash_table_iter_next (&iter, &key, &value)) { + const char *keystr = key; + if (strncmp (keystr, "concat-", 7) == 0) + continue; + if (strcmp (keystr, "text") == 0 || + strcmp (keystr, "index") == 0) + continue; + if (strcmp (keystr, "class") == 0) { + GValue *val; + val = g_slice_new0 (GValue); + g_value_init (val, G_TYPE_UINT); + g_value_copy (value, val); + g_hash_table_insert (full, key, val); + } else { + GValue *val; + val = g_slice_new0 (GValue); + g_value_init (val, G_TYPE_STRING); + g_value_copy (value, val); + g_hash_table_insert (full, key, val); + } + } + + g_hash_table_insert (full, "index", simple_uint_value (mpm->index)); + g_hash_table_insert (full, "text", simple_string_value (fulltext)); + g_free (fulltext); + + return full; +} + +static void +cmti_received_has_sms (MMModemGsmSms *modem, + GHashTable *properties, + GError *error, + gpointer user_data) +{ + MMGenericGsm *self = MM_GENERIC_GSM (user_data); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + guint idx; + gboolean complete; + GValue *ref; + + if (properties == NULL) + return; + + ref = g_hash_table_lookup (properties, "concat-reference"); + if (ref == NULL) { + /* single-part message */ + GValue *idxval = g_hash_table_lookup (properties, "index"); + if (idxval == NULL) + return; + idx = g_value_get_uint (idxval); + complete = TRUE; + } else { + SMSMultiPartMessage *mpm; + mpm = g_hash_table_lookup (priv->sms_parts, + GUINT_TO_POINTER (g_value_get_uint (ref))); + if (mpm == NULL) + return; + idx = mpm->index; + complete = (mpm->missing == 0); + } + + if (complete) + mm_modem_gsm_sms_completed (MM_MODEM_GSM_SMS (self), idx, TRUE); + + mm_modem_gsm_sms_received (MM_MODEM_GSM_SMS (self), idx, complete); +} + +static void sms_get_invoke (MMCallbackInfo *info); +static void sms_get_done (MMAtSerialPort *port, GString *response, + GError *error, gpointer user_data); + static void cmti_received (MMAtSerialPort *port, GMatchInfo *info, @@ -1336,8 +1579,9 @@ cmti_received (MMAtSerialPort *port, { MMGenericGsm *self = MM_GENERIC_GSM (user_data); MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + MMCallbackInfo *cbinfo; guint idx = 0; - char *str; + char *str, *command; str = g_match_info_fetch (info, 2); if (str) @@ -1351,12 +1595,24 @@ cmti_received (MMAtSerialPort *port, /* Nothing is currently stored in the hash table - presence is all that matters. */ g_hash_table_insert (priv->sms_present, GINT_TO_POINTER (idx), NULL); - /* todo: parse pdu to know if the sms is complete */ - mm_modem_gsm_sms_received (MM_MODEM_GSM_SMS (self), - idx, - TRUE); + /* Retrieve the message */ + cbinfo = mm_callback_info_new_full (MM_MODEM (user_data), + sms_get_invoke, + G_CALLBACK (cmti_received_has_sms), + user_data); + mm_callback_info_set_data (cbinfo, + "complete-sms-only", + GUINT_TO_POINTER (FALSE), + NULL); - /* todo: send mm_modem_gsm_sms_completed if complete */ + if (priv->sms_fetch_pending != 0) { + mm_err("sms_fetch_pending is %d, not 0", priv->sms_fetch_pending); + } + priv->sms_fetch_pending = idx; + + command = g_strdup_printf ("+CMGR=%d", idx); + mm_at_serial_port_queue_command (port, command, 10, sms_get_done, cbinfo); + /* Don't want to signal received here before we have the contents */ } static void @@ -1428,6 +1684,96 @@ cusd_enable_cb (MMAtSerialPort *port, MM_GENERIC_GSM_GET_PRIVATE (user_data)->ussd_enabled = TRUE; } +static void +sms_set_format_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMGenericGsm *self = MM_GENERIC_GSM (user_data); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + if (error) { + mm_warn ("(%s): failed to set SMS mode, assuming text mode", + mm_port_get_device (MM_PORT (port))); + priv->sms_pdu_mode = FALSE; + priv->sms_pdu_supported = FALSE; + } else { + mm_info ("(%s): using %s mode for SMS", + mm_port_get_device (MM_PORT (port)), + priv->sms_pdu_mode ? "PDU" : "text"); + } +} + + +#define CMGF_TAG "+CMGF:" + +static void +sms_get_format_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMGenericGsm *self; + MMGenericGsmPrivate *priv; + const char *reply; + GRegex *r; + GMatchInfo *match_info; + char *s; + int min = -1, max = -1; + + if (error) { + mm_warn ("(%s): failed to query SMS mode, assuming text mode", + mm_port_get_device (MM_PORT (port))); + return; + } + + /* Strip whitespace and response tag */ + reply = response->str; + if (g_str_has_prefix (reply, CMGF_TAG)) + reply += strlen (CMGF_TAG); + while (isspace (*reply)) + reply++; + + r = g_regex_new ("\\(?\\s*(\\d+)\\s*[-,]?\\s*(\\d+)?\\s*\\)?", 0, 0, NULL); + if (!r) { + mm_warn ("(%s): failed to parse CMGF query result", mm_port_get_device (MM_PORT (port))); + return; + } + + self = MM_GENERIC_GSM (user_data); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) { + s = g_match_info_fetch (match_info, 1); + if (s) + min = atoi (s); + g_free (s); + + s = g_match_info_fetch (match_info, 2); + if (s) + max = atoi (s); + g_free (s); + + /* If the modem only supports PDU mode, use PDUs. + * FIXME: when the PDU code is more robust, default to PDU if the + * modem supports it. + */ + if (min == 0 && max < 1) { + /* Will get reset to FALSE on receipt of error */ + priv->sms_pdu_mode = TRUE; + mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=0", 3, sms_set_format_cb, self); + } else + mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=1", 3, sms_set_format_cb, self); + + /* Save whether PDU mode is supported so we can fall back to it if text fails */ + if (min == 0) + priv->sms_pdu_supported = TRUE; + } + g_match_info_free (match_info); + + g_regex_unref (r); +} + void mm_generic_gsm_enable_complete (MMGenericGsm *self, GError *error, @@ -1472,6 +1818,9 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, /* Enable SMS notifications */ mm_at_serial_port_queue_command (priv->primary, "+CNMI=2,1,2,1,0", 3, NULL, NULL); + /* Check and enable the right SMS mode */ + mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=?", 3, sms_get_format_cb, self); + /* Enable USSD notifications */ mm_at_serial_port_queue_command (priv->primary, "+CUSD=1", 3, cusd_enable_cb, self); @@ -1523,6 +1872,27 @@ enable_done (MMAtSerialPort *port, info); } +static void +enable_power_up_check_needed_done (MMModem *self, + guint32 needed, + GError *error, + gpointer user_data) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + char *cmd = NULL; + + if (needed) + g_object_get (G_OBJECT (self), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL); + else + mm_dbg ("Power-up not needed, skipping..."); + + if (cmd && strlen (cmd)) + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (priv->primary), cmd, 5, enable_done, user_data); + else + enable_done (MM_AT_SERIAL_PORT (priv->primary), NULL, NULL, user_data); + g_free (cmd); +} + static void init_done (MMAtSerialPort *port, GString *response, @@ -1556,12 +1926,13 @@ init_done (MMAtSerialPort *port, mm_at_serial_port_queue_command (port, cmd, 2, NULL, NULL); g_free (cmd); - g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL); - if (cmd && strlen (cmd)) - mm_at_serial_port_queue_command (port, cmd, 5, enable_done, user_data); + /* Plugins can now check if they need the power up command or not */ + if (MM_GENERIC_GSM_GET_CLASS (info->modem)->do_enable_power_up_check_needed) + MM_GENERIC_GSM_GET_CLASS (info->modem)->do_enable_power_up_check_needed (MM_GENERIC_GSM (info->modem), + enable_power_up_check_needed_done, + info); else - enable_done (port, NULL, NULL, user_data); - g_free (cmd); + enable_power_up_check_needed_done (info->modem, TRUE, NULL, info); } static void @@ -1733,6 +2104,22 @@ disable_flash_done (MMSerialPort *port, g_free (cmd); } +static void +mark_disabled (gpointer user_data) +{ + MMCallbackInfo *info = user_data; + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLING, + MM_MODEM_STATE_REASON_NONE); + + if (mm_port_get_connected (MM_PORT (priv->primary))) + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, TRUE, disable_flash_done, info); + else + disable_flash_done (MM_SERIAL_PORT (priv->primary), NULL, info); +} + static void secondary_unsolicited_done (MMAtSerialPort *port, GString *response, @@ -1740,6 +2127,7 @@ secondary_unsolicited_done (MMAtSerialPort *port, gpointer user_data) { mm_serial_port_close_force (MM_SERIAL_PORT (port)); + mark_disabled (user_data); } static void @@ -1779,13 +2167,6 @@ disable (MMModem *modem, update_lac_ci (self, 0, 0, 1); _internal_update_access_technology (self, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN); - /* Clean up the secondary port if it's open */ - if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) { - mm_at_serial_port_queue_command (priv->secondary, "+CREG=0", 3, NULL, NULL); - mm_at_serial_port_queue_command (priv->secondary, "+CGREG=0", 3, NULL, NULL); - mm_at_serial_port_queue_command (priv->secondary, "+CMER=0", 3, secondary_unsolicited_done, NULL); - } - info = mm_callback_info_new (modem, callback, user_data); /* Cache the previous state so we can reset it if the operation fails */ @@ -1795,14 +2176,14 @@ disable (MMModem *modem, GUINT_TO_POINTER (state), NULL); - mm_modem_set_state (MM_MODEM (info->modem), - MM_MODEM_STATE_DISABLING, - MM_MODEM_STATE_REASON_NONE); - - if (mm_port_get_connected (MM_PORT (priv->primary))) - mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, TRUE, disable_flash_done, info); - else - disable_flash_done (MM_SERIAL_PORT (priv->primary), NULL, info); + /* Clean up the secondary port if it's open */ + if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) { + mm_dbg("Shutting down secondary port"); + mm_at_serial_port_queue_command (priv->secondary, "+CREG=0", 3, NULL, NULL); + mm_at_serial_port_queue_command (priv->secondary, "+CGREG=0", 3, NULL, NULL); + mm_at_serial_port_queue_command (priv->secondary, "+CMER=0", 3, secondary_unsolicited_done, info); + } else + mark_disabled (info); } static void @@ -2470,35 +2851,6 @@ reg_info_updated (MMGenericGsm *self, } } -static void -convert_operator_from_ucs2 (char **operator) -{ - const char *p; - char *converted; - size_t len; - - g_return_if_fail (operator != NULL); - g_return_if_fail (*operator != NULL); - - p = *operator; - len = strlen (p); - - /* Len needs to be a multiple of 4 for UCS2 */ - if ((len < 4) || ((len % 4) != 0)) - return; - - while (*p) { - if (!isxdigit (*p++)) - return; - } - - converted = mm_modem_charset_hex_to_utf8 (*operator, MM_MODEM_CHARSET_UCS2); - if (converted) { - g_free (*operator); - *operator = converted; - } -} - static char * parse_operator (const char *reply, MMModemCharset cur_charset) { @@ -2528,7 +2880,7 @@ parse_operator (const char *reply, MMModemCharset cur_charset) * character set. */ if (cur_charset == MM_MODEM_CHARSET_UCS2) - convert_operator_from_ucs2 (&operator); + operator = mm_charset_take_and_convert_to_utf8 (operator, MM_MODEM_CHARSET_UCS2); /* Ensure the operator name is valid UTF-8 so that we can send it * through D-Bus and such. @@ -2828,7 +3180,7 @@ handle_reg_status_response (MMGenericGsm *self, guint32 status = 0; gulong lac = 0, ci = 0; gint act = -1; - gboolean cgreg = FALSE; + gboolean cgreg = FALSE, parsed; guint i; /* Try to match the response */ @@ -2848,47 +3200,38 @@ handle_reg_status_response (MMGenericGsm *self, } /* And parse it */ - if (!mm_gsm_parse_creg_response (match_info, &status, &lac, &ci, &act, &cgreg, error)) { - g_match_info_free (match_info); - return FALSE; - } - - /* Success; update cached location information */ - update_lac_ci (self, lac, ci, cgreg ? 1 : 0); - - /* Only update access technology if it appeared in the CREG/CGREG response */ - if (act != -1) - mm_generic_gsm_update_access_technology (self, etsi_act_to_mm_act (act)); - - if (status >= 0) { - /* Update cached registration status */ - reg_status_updated (self, cgreg_to_reg_type (cgreg), status, NULL); + parsed = mm_gsm_parse_creg_response (match_info, &status, &lac, &ci, &act, &cgreg, error); + g_match_info_free (match_info); + if (parsed) { + /* Success; update cached location information */ + update_lac_ci (self, lac, ci, cgreg ? 1 : 0); + + /* Only update access technology if it appeared in the CREG/CGREG response */ + if (act != -1) + mm_generic_gsm_update_access_technology (self, etsi_act_to_mm_act (act)); + + if (status >= 0) { + /* Update cached registration status */ + reg_status_updated (self, cgreg_to_reg_type (cgreg), status, NULL); + } } - return TRUE; + return parsed; } -#define CGREG_TRIED_TAG "cgreg-tried" +#define CS_ERROR_TAG "cs-error" +#define CS_DONE_TAG "cs-complete" +#define PS_ERROR_TAG "ps-error" +#define PS_DONE_TAG "ps-complete" static void -get_reg_status_done (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data) +check_reg_status_done (MMCallbackInfo *info) { - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMGenericGsm *self; - MMGenericGsmPrivate *priv; - guint id; + MMGenericGsm *self = MM_GENERIC_GSM (info->modem); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + GError *cs_error, *ps_error; MMModemGsmNetworkRegStatus status; - - /* If the modem has already been removed, return without - * scheduling callback */ - if (mm_callback_info_check_modem_removed (info)) - return; - - self = MM_GENERIC_GSM (info->modem); - priv = MM_GENERIC_GSM_GET_PRIVATE (self); + guint id; /* This function should only get called during the connect sequence when * polling for registration state, since explicit registration requests @@ -2896,46 +3239,38 @@ get_reg_status_done (MMAtSerialPort *port, */ g_return_if_fail (info == priv->pending_reg_info); - if (error) { - gboolean cgreg_tried = !!mm_callback_info_get_data (info, CGREG_TRIED_TAG); - - /* If this was a +CREG error, try +CGREG. Some devices (blackberries) - * respond to +CREG with an error but return a valid +CGREG response. - * So try both. If we get an error from both +CREG and +CGREG, that's - * obviously a hard fail. - */ - if (cgreg_tried == FALSE) { - mm_callback_info_set_data (info, CGREG_TRIED_TAG, GUINT_TO_POINTER (TRUE), NULL); - mm_at_serial_port_queue_command (port, "+CGREG?", 10, get_reg_status_done, info); - return; - } else { - info->error = g_error_copy (error); - goto reg_done; - } - } - - /* The unsolicited registration state handlers will intercept the CREG - * response and update the cached registration state for us, so we usually - * just need to check the cached state here. - */ + /* Only process when both CS and PS checks are both done */ + if ( !mm_callback_info_get_data (info, CS_DONE_TAG) + || !mm_callback_info_get_data (info, PS_DONE_TAG)) + return; - if (strlen (response->str)) { - /* But just in case the unsolicited handlers doesn't do it... */ - if (!handle_reg_status_response (self, response, &info->error)) - goto reg_done; + /* If both CS and PS registration checks returned errors we fail */ + cs_error = mm_callback_info_get_data (info, CS_ERROR_TAG); + ps_error = mm_callback_info_get_data (info, PS_ERROR_TAG); + if (cs_error && ps_error) { + /* Prefer the PS error */ + info->error = g_error_copy (ps_error); + goto reg_done; } status = gsm_reg_status (self, NULL); if ( status != MM_MODEM_GSM_NETWORK_REG_STATUS_HOME && status != MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING && status != MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED) { + + /* Clear state that should be reset every poll */ + mm_callback_info_set_data (info, CS_DONE_TAG, NULL, NULL); + mm_callback_info_set_data (info, CS_ERROR_TAG, NULL, NULL); + mm_callback_info_set_data (info, PS_DONE_TAG, NULL, NULL); + mm_callback_info_set_data (info, PS_ERROR_TAG, NULL, NULL); + /* If we're still waiting for automatic registration to complete or * fail, check again in a few seconds. */ id = g_timeout_add_seconds (1, reg_status_again, info); mm_callback_info_set_data (info, REG_STATUS_AGAIN_TAG, - GUINT_TO_POINTER (id), - reg_status_again_remove); + GUINT_TO_POINTER (id), + reg_status_again_remove); return; } @@ -2944,10 +3279,64 @@ reg_done: mm_generic_gsm_pending_registration_stop (self); } +static void +generic_reg_status_done (MMCallbackInfo *info, + GString *response, + GError *error, + const char *error_tag, + const char *done_tag) +{ + MMGenericGsm *self = MM_GENERIC_GSM (info->modem); + GError *local = NULL; + + if (error) + local = g_error_copy (error); + else if (strlen (response->str)) { + /* Unsolicited registration status handlers will usually process the + * response for us, but just in case they don't, do that here. + */ + if (handle_reg_status_response (self, response, &local) == TRUE) + g_assert_no_error (local); + } + + if (local) + mm_callback_info_set_data (info, error_tag, local, (GDestroyNotify) g_error_free); + mm_callback_info_set_data (info, done_tag, GUINT_TO_POINTER (1), NULL); +} + +static void +get_ps_reg_status_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (mm_callback_info_check_modem_removed (info) == FALSE) { + generic_reg_status_done (info, response, error, PS_ERROR_TAG, PS_DONE_TAG); + check_reg_status_done (info); + } +} + +static void +get_cs_reg_status_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (mm_callback_info_check_modem_removed (info) == FALSE) { + generic_reg_status_done (info, response, error, CS_ERROR_TAG, CS_DONE_TAG); + check_reg_status_done (info); + } +} + static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info) { - mm_at_serial_port_queue_command (port, "+CREG?", 10, get_reg_status_done, info); + mm_at_serial_port_queue_command (port, "+CREG?", 10, get_cs_reg_status_done, info); + mm_at_serial_port_queue_command (port, "+CGREG?", 10, get_ps_reg_status_done, info); } static void @@ -2976,6 +3365,10 @@ register_done (MMAtSerialPort *port, if (priv->pending_reg_info) { g_warn_if_fail (info == priv->pending_reg_info); + if (error) { + g_clear_error (&info->error); + info->error = g_error_copy (error); + } /* Don't use cached registration state here since it could be up to * 30 seconds old. Get fresh registration state. @@ -3064,9 +3457,9 @@ do_register (MMModemGsmNetwork *modem, * complete. For those devices that delay the +COPS response (hso) the * callback will be called from register_done(). For those devices that * return the +COPS response immediately, we'll poll the registration state - * and call the callback from get_reg_status_done() in response to the - * polled response. The registration timeout will only be triggered when - * the +COPS response is never received. + * and call the callback from get_[cs|ps]_reg_status_done() in response to + * the polled response. The registration timeout will only be triggered + * when the +COPS response is never received. */ mm_callback_info_ref (info); @@ -3547,9 +3940,13 @@ cid_range_read (MMAtSerialPort *port, g_match_info_next (match_info, NULL); } - if (cid == 0) + if (cid == 0) { /* Choose something */ cid = 1; + } + + g_match_info_free (match_info); + g_regex_unref (r); } } else info->error = g_error_new_literal (MM_MODEM_ERROR, @@ -3780,7 +4177,7 @@ get_csq_done (MMAtSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - char *reply = response->str; + char *reply; gboolean parsed = FALSE; /* If the modem has already been removed, return without @@ -3793,6 +4190,7 @@ get_csq_done (MMAtSerialPort *port, goto done; } + reply = response->str; if (!strncmp (reply, "+CSQ: ", 6)) { /* Got valid reply */ int quality; @@ -4191,7 +4589,22 @@ mm_generic_gsm_get_charset (MMGenericGsm *self) /*****************************************************************************/ /* MMModemGsmSms interface */ +static void +sms_send_invoke (MMCallbackInfo *info) +{ + MMModemGsmSmsSendFn callback = (MMModemGsmSmsSendFn) info->callback; + + callback (MM_MODEM_GSM_SMS (info->modem), + mm_callback_info_get_data (info, "indexes"), + info->error, + info->user_data); +} +static void +free_indexes (gpointer data) +{ + g_array_free ((GArray *) data, TRUE); +} static void sms_send_done (MMAtSerialPort *port, @@ -4200,15 +4613,59 @@ sms_send_done (MMAtSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + const char *p, *pdu; + unsigned long num; + GArray *indexes = NULL; + guint32 idx = 0; + guint cmgs_pdu_size; + char *command; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; - if (error) - info->error = g_error_copy (error); + if (error) { + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + /* If there was an error sending in text mode the retry with the PDU; + * text mode is pretty dumb on most devices and often fails. Later we'll + * just use text mode exclusively. + */ + pdu = mm_callback_info_get_data (info, "pdu"); + if (priv->sms_pdu_mode == FALSE && priv->sms_pdu_supported && pdu) { + cmgs_pdu_size = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "cmgs-pdu-size")); + g_assert (cmgs_pdu_size); + command = g_strdup_printf ("+CMGS=%d\r%s\x1a", cmgs_pdu_size, pdu); + mm_at_serial_port_queue_command (port, command, 10, sms_send_done, info); + g_free (command); + + /* Clear the PDU data so we don't keep getting here */ + mm_callback_info_set_data (info, "pdu", NULL, NULL); + return; + } + + /* Otherwise it's a hard error */ + info->error = g_error_copy (error); + } else { + /* If the response happens to have a ">" in it from the interactive + * handling of the CMGS command, skip it. + */ + p = strchr (response->str, '+'); + if (p && *p) { + /* Check for the message index */ + p = mm_strip_tag (p, "+CMGS:"); + if (p && *p) { + errno = 0; + num = strtoul (p, NULL, 10); + if ((num < G_MAXUINT32) && (errno == 0)) + idx = (guint32) num; + } + } + indexes = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 1); + g_array_append_val (indexes, idx); + mm_callback_info_set_data (info, "indexes", indexes, free_indexes); + } mm_callback_info_schedule (info); } @@ -4219,31 +4676,59 @@ sms_send (MMModemGsmSms *modem, const char *smsc, guint validity, guint class, - MMModemFn callback, + MMModemGsmSmsSendFn callback, gpointer user_data) { MMCallbackInfo *info; + MMGenericGsm *self = MM_GENERIC_GSM (modem); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); char *command; MMAtSerialPort *port; + guint8 *pdu; + guint pdulen = 0, msgstart = 0; + char *hex; - info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + info = mm_callback_info_new_full (MM_MODEM (modem), + sms_send_invoke, + G_CALLBACK (callback), + user_data); - port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); + port = mm_generic_gsm_get_best_at_port (self, &info->error); if (!port) { mm_callback_info_schedule (info); return; } - /* FIXME: use the PDU mode instead */ - mm_at_serial_port_queue_command (port, "AT+CMGF=1", 3, NULL, NULL); + /* Always create a PDU since we might need it for fallback from text mode */ + pdu = sms_create_submit_pdu (number, text, smsc, validity, class, &pdulen, &msgstart, &info->error); + if (!pdu) { + mm_callback_info_schedule (info); + return; + } + + hex = utils_bin2hexstr (pdu, pdulen); + g_free (pdu); + if (hex == NULL) { + g_set_error_literal (&info->error, + MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Not enough memory to send SMS PDU"); + mm_callback_info_schedule (info); + return; + } + + mm_callback_info_set_data (info, "pdu", hex, g_free); + mm_callback_info_set_data (info, "cmgs-pdu-size", GUINT_TO_POINTER (pdulen - msgstart), NULL); + if (priv->sms_pdu_mode) { + /* CMGS length is the size of the PDU without SMSC information */ + command = g_strdup_printf ("+CMGS=%d\r%s\x1a", pdulen - msgstart, hex); + } else + command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text); - command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text); mm_at_serial_port_queue_command (port, command, 10, sms_send_done, info); g_free (command); } - - static void sms_get_done (MMAtSerialPort *port, GString *response, @@ -4251,9 +4736,15 @@ sms_get_done (MMAtSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); GHashTable *properties; - int rv, status, tpdu_len, offset; + int rv, status, tpdu_len; + guint idx; char pdu[SMS_MAX_PDU_LEN + 1]; + gboolean look_for_complete; + + idx = priv->sms_fetch_pending; + priv->sms_fetch_pending = 0; /* If the modem has already been removed, return without * scheduling callback */ @@ -4266,9 +4757,9 @@ sms_get_done (MMAtSerialPort *port, } /* 344 == SMS_MAX_PDU_LEN */ - rv = sscanf (response->str, "+CMGR: %d,,%d %344s %n", - &status, &tpdu_len, pdu, &offset); - if (rv != 4) { + rv = sscanf (response->str, "+CMGR: %d,,%d %344s", + &status, &tpdu_len, pdu); + if (rv != 3) { info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Failed to parse CMGR response (parsed %d items)", @@ -4281,8 +4772,24 @@ sms_get_done (MMAtSerialPort *port, goto out; } - mm_callback_info_set_data (info, GS_HASH_TAG, properties, - (GDestroyNotify) g_hash_table_unref); + g_hash_table_insert (properties, "index", simple_uint_value (idx)); + sms_cache_insert (info->modem, properties, idx); + + look_for_complete = GPOINTER_TO_UINT (mm_callback_info_get_data(info, + "complete-sms-only")); + + if (look_for_complete == TRUE) { + /* + * If this is a standalone message, or the key part of a + * multipart message, pass it along, otherwise report that there's + * no such message. + */ + properties = sms_cache_lookup_full (info->modem, properties, + &info->error); + } + if (properties) + mm_callback_info_set_data (info, GS_HASH_TAG, properties, + (GDestroyNotify) g_hash_table_unref); out: mm_callback_info_schedule (info); @@ -4307,11 +4814,35 @@ sms_get (MMModemGsmSms *modem, MMCallbackInfo *info; char *command; MMAtSerialPort *port; + MMGenericGsmPrivate *priv = + MM_GENERIC_GSM_GET_PRIVATE (MM_GENERIC_GSM (modem)); + GHashTable *properties; + GError *error = NULL; + + properties = g_hash_table_lookup (priv->sms_contents, GUINT_TO_POINTER (idx)); + if (properties != NULL) { + g_hash_table_ref (properties); + properties = sms_cache_lookup_full (MM_MODEM (modem), properties, &error); + if (properties == NULL) { + error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "No SMS found"); + } + callback (modem, properties, error, user_data); + if (properties != NULL) + g_hash_table_unref (properties); + g_error_free (error); + return; + } info = mm_callback_info_new_full (MM_MODEM (modem), sms_get_invoke, G_CALLBACK (callback), user_data); + mm_callback_info_set_data (info, + "complete-sms-only", + GUINT_TO_POINTER (TRUE), + NULL); port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); if (!port) { @@ -4319,10 +4850,18 @@ sms_get (MMModemGsmSms *modem, return; } - command = g_strdup_printf ("+CMGR=%d\r\n", idx); + command = g_strdup_printf ("+CMGR=%d", idx); + priv->sms_fetch_pending = idx; mm_at_serial_port_queue_command (port, command, 10, sms_get_done, info); } +typedef struct { + MMGenericGsmPrivate *priv; + MMCallbackInfo *info; + SMSMultiPartMessage *mpm; + int deleting; +} SMSDeleteProgress; + static void sms_delete_done (MMAtSerialPort *port, GString *response, @@ -4342,6 +4881,50 @@ sms_delete_done (MMAtSerialPort *port, mm_callback_info_schedule (info); } +static void +sms_delete_multi_next (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + SMSDeleteProgress *progress = (SMSDeleteProgress *)user_data; + + /* If the modem has already been removed, return without + * scheduling callback */ + if (mm_callback_info_check_modem_removed (progress->info)) + goto done; + + if (error) + progress->info->error = g_error_copy (error); + + for (progress->deleting++ ; + progress->deleting < progress->mpm->numparts ; + progress->deleting++) + if (progress->mpm->parts[progress->deleting] != 0) + break; + if (progress->deleting < progress->mpm->numparts) { + GHashTable *properties; + char *command; + guint idx; + + idx = progress->mpm->parts[progress->deleting]; + command = g_strdup_printf ("+CMGD=%d", idx); + mm_at_serial_port_queue_command (port, command, 10, + sms_delete_multi_next, progress); + properties = g_hash_table_lookup (progress->priv->sms_contents, GUINT_TO_POINTER (idx)); + g_hash_table_remove (progress->priv->sms_contents, GUINT_TO_POINTER (idx)); + g_hash_table_remove (progress->priv->sms_present, GUINT_TO_POINTER (idx)); + g_hash_table_unref (properties); + return; + } + + mm_callback_info_schedule (progress->info); +done: + g_free (progress->mpm->parts); + g_free (progress->mpm); + g_free (progress); +} + static void sms_delete (MMModemGsmSms *modem, guint idx, @@ -4352,18 +4935,262 @@ sms_delete (MMModemGsmSms *modem, char *command; MMAtSerialPort *port; MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (MM_GENERIC_GSM (modem)); + GHashTable *properties; + MMAtSerialResponseFn next_callback; + GValue *ref; info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); - g_hash_table_remove (priv->sms_present, GINT_TO_POINTER (idx)); + + properties = g_hash_table_lookup (priv->sms_contents, GINT_TO_POINTER (idx)); + if (properties == NULL) { + /* + * TODO(njw): This assumes our cache is valid. If we doubt this, we should just + * run the delete anyway and let that return the nonexistent-message error. + */ + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "No SMS to delete"); + mm_callback_info_schedule (info); + return; + } port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); if (!port) { mm_callback_info_schedule (info); + g_hash_table_remove (priv->sms_contents, GINT_TO_POINTER (idx)); + g_hash_table_unref (properties); return; } - command = g_strdup_printf ("+CMGD=%d\r\n", idx); - mm_at_serial_port_queue_command (port, command, 10, sms_delete_done, info); + user_data = info; + next_callback = sms_delete_done; + ref = g_hash_table_lookup (properties, "concat-reference"); + if (ref != NULL) { + SMSMultiPartMessage *mpm; + SMSDeleteProgress *progress; + guint refnum; + + refnum = g_value_get_uint (ref); + mpm = g_hash_table_lookup (priv->sms_parts, GUINT_TO_POINTER (refnum)); + if (mpm == NULL) { + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Internal error - no part array for multipart SMS"); + mm_callback_info_schedule (info); + g_hash_table_remove (priv->sms_contents, GINT_TO_POINTER (idx)); + g_hash_table_unref (properties); + return; + } + /* Only allow the delete operation on the main index number. */ + if (idx != mpm->index) { + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "No SMS to delete"); + mm_callback_info_schedule (info); + return; + } + + g_hash_table_remove (priv->sms_parts, GUINT_TO_POINTER (refnum)); + progress = g_malloc0 (sizeof(*progress)); + progress->priv = priv; + progress->info = info; + progress->mpm = mpm; + for (progress->deleting = 0 ; + progress->deleting < mpm->numparts ; + progress->deleting++) + if (mpm->parts[progress->deleting] != 0) + break; + user_data = progress; + next_callback = sms_delete_multi_next; + idx = progress->mpm->parts[progress->deleting]; + properties = g_hash_table_lookup (priv->sms_contents, GINT_TO_POINTER (idx)); + } + g_hash_table_remove (priv->sms_contents, GUINT_TO_POINTER (idx)); + g_hash_table_remove (priv->sms_present, GUINT_TO_POINTER (idx)); + g_hash_table_unref (properties); + + command = g_strdup_printf ("+CMGD=%d", idx); + mm_at_serial_port_queue_command (port, command, 10, next_callback, + user_data); +} + +static gboolean +pdu_parse_cmgl (MMGenericGsm *self, const char *response, GError **error) +{ + int rv, status, tpdu_len, offset; + GHashTable *properties; + + while (*response) { + int idx; + char pdu[SMS_MAX_PDU_LEN + 1]; + + rv = sscanf (response, "+CMGL: %d,%d,,%d %344s %n", + &idx, &status, &tpdu_len, pdu, &offset); + if (4 != rv) { + g_set_error (error, + MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Failed to parse CMGL response: expected 4 results got %d", rv); + mm_err("Couldn't parse response to SMS LIST (%d)", rv); + return FALSE; + } + response += offset; + + properties = sms_parse_pdu (pdu, NULL); + if (properties) { + g_hash_table_insert (properties, "index", simple_uint_value (idx)); + sms_cache_insert (MM_MODEM (self), properties, idx); + /* The cache holds a reference, so we don't need it anymore */ + g_hash_table_unref (properties); + } + } + + return TRUE; +} + +static gboolean +get_match_uint (GMatchInfo *m, guint match_index, guint *out_val) +{ + char *s; + unsigned long num; + + g_return_val_if_fail (out_val != NULL, FALSE); + + s = g_match_info_fetch (m, match_index); + g_return_val_if_fail (s != NULL, FALSE); + + errno = 0; + num = strtoul (s, NULL, 10); + g_free (s); + + if (num <= 1000 && errno == 0) { + *out_val = (guint) num; + return TRUE; + } + return FALSE; +} + +static char * +get_match_string_unquoted (GMatchInfo *m, guint match_index) +{ + char *s, *p, *q, *ret = NULL; + + q = s = g_match_info_fetch (m, match_index); + g_return_val_if_fail (s != NULL, FALSE); + + /* remove quotes */ + if (*q == '"') + q++; + p = strchr (q, '"'); + if (p) + *p = '\0'; + if (*q) + ret = g_strdup (q); + g_free (s); + return ret; +} + +static gboolean +text_parse_cmgl (MMGenericGsm *self, const char *response, GError **error) +{ + MMGenericGsmPrivate *priv; + GRegex *r; + GMatchInfo *match_info = NULL; + + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + /* +CMGL: ,,,[alpha], */ + r = g_regex_new ("\\+CMGL:\\s*(\\d+)\\s*,\\s*([^,]*),\\s*([^,]*),\\s*([^,]*),\\s*([^\\r\\n]*)\\r\\n([^\\r\\n]*)", 0, 0, NULL); + g_assert (r); + + if (!g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, NULL)) { + g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Failed to parse CMGL response"); + mm_err("Couldn't parse response to SMS LIST"); + g_regex_unref (r); + return FALSE; + } + + while (g_match_info_matches (match_info)) { + GHashTable *properties; + guint matches, idx; + char *number = NULL, *timestamp, *text, *ucs2_text; + gsize ucs2_len = 0; + GByteArray *data; + + matches = g_match_info_get_match_count (match_info); + if (matches != 7) { + mm_dbg ("Failed to match entire CMGL response (count %d)", matches); + goto next; + } + + if (!get_match_uint (match_info, 1, &idx)) { + mm_dbg ("Failed to convert message index"); + goto next; + } + + /* */ + + /* Get and parse number */ + number = get_match_string_unquoted (match_info, 3); + if (!number) { + mm_dbg ("Failed to get message sender number"); + goto next; + } + number = mm_charset_take_and_convert_to_utf8 (number, + priv->cur_charset); + + /* Get and parse timestamp (always expected in ASCII) */ + timestamp = get_match_string_unquoted (match_info, 5); + + /* Get and parse text */ + text = mm_charset_take_and_convert_to_utf8 (g_match_info_fetch (match_info, 6), + priv->cur_charset); + + /* The raw SMS data can only be GSM, UCS2, or unknown (8-bit), so we + * need to convert to UCS2 here. + */ + ucs2_text = g_convert (text, -1, "UCS-2BE//TRANSLIT", "UTF-8", NULL, &ucs2_len, NULL); + g_assert (ucs2_text); + data = g_byte_array_sized_new (ucs2_len); + g_byte_array_append (data, (const guint8 *) ucs2_text, ucs2_len); + g_free (ucs2_text); + + properties = sms_properties_hash_new (NULL, + number, + timestamp, + text, + data, + 2, /* DCS = UCS2 */ + 0); /* class */ + g_assert (properties); + + g_free (number); + g_free (timestamp); + g_free (text); + g_byte_array_free (data, TRUE); + + g_hash_table_insert (properties, "index", simple_uint_value (idx)); + sms_cache_insert (MM_MODEM (self), properties, idx); + /* The cache holds a reference, so we don't need it anymore */ + g_hash_table_unref (properties); + +next: + g_match_info_next (match_info, NULL); + } + g_match_info_free (match_info); + + g_regex_unref (r); + return TRUE; +} + +static void +free_list_results (gpointer data) +{ + GPtrArray *results = (GPtrArray *) data; + + g_ptr_array_foreach (results, (GFunc) g_hash_table_unref, NULL); + g_ptr_array_free (results, TRUE); } static void @@ -4373,54 +5200,44 @@ sms_list_done (MMAtSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMGenericGsm *self = MM_GENERIC_GSM (info->modem); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + GHashTableIter iter; + GHashTable *properties = NULL; GPtrArray *results = NULL; - int rv, status, tpdu_len, offset; - char *rstr; + gboolean success; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; - if (error) + if (error) { info->error = g_error_copy (error); - else { + mm_callback_info_schedule (info); + return; + } + + if (priv->sms_pdu_mode) + success = pdu_parse_cmgl (self, response->str, &info->error); + else + success = text_parse_cmgl (self, response->str, &info->error); + + if (success) { results = g_ptr_array_new (); - rstr = response->str; - - while (*rstr) { - GHashTable *properties; - GError *local; - int idx; - char pdu[SMS_MAX_PDU_LEN + 1]; - - rv = sscanf (rstr, "+CMGL: %d,%d,,%d %344s %n", - &idx, &status, &tpdu_len, pdu, &offset); - if (4 != rv) { - mm_err("Couldn't parse response to SMS LIST (%d)", rv); - break; - } - rstr += offset; - properties = sms_parse_pdu (pdu, &local); - if (properties) { - g_hash_table_insert (properties, "index", - simple_uint_value (idx)); + /* Add all the complete messages to the results */ + g_hash_table_iter_init (&iter, priv->sms_contents); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &properties)) { + g_hash_table_ref (properties); + g_clear_error (&info->error); + properties = sms_cache_lookup_full (info->modem, properties, NULL); + if (properties) g_ptr_array_add (results, properties); - } else { - /* Ignore the error */ - g_clear_error(&local); - } } - /* - * todo(njw): mm_gsm_destroy_scan_data does what we want - * (destroys a GPtrArray of g_hash_tables), but it should be - * renamed to describe that or there should be a function - * named for what we're doing here. - */ + if (results) - mm_callback_info_set_data (info, "list-sms", results, - mm_gsm_destroy_scan_data); + mm_callback_info_set_data (info, "list-sms", results, free_list_results); } mm_callback_info_schedule (info); @@ -4456,7 +5273,10 @@ sms_list (MMModemGsmSms *modem, return; } - command = g_strdup_printf ("+CMGL=4\r\n"); + if (MM_GENERIC_GSM_GET_PRIVATE (modem)->sms_pdu_mode) + command = g_strdup_printf ("+CMGL=4"); + else + command = g_strdup_printf ("+CMGL=\"ALL\""); mm_at_serial_port_queue_command (port, command, 10, sms_list_done, info); } @@ -4544,6 +5364,7 @@ decode_ussd_response (MMGenericGsm *self, char **items, **iter, *p; char *str = NULL; gint encoding = -1; + char *decoded; /* Look for the first ',' */ p = strchr (reply, ','); @@ -4563,6 +5384,9 @@ decode_ussd_response (MMGenericGsm *self, } } + if (!str) + return NULL; + /* Strip quotes */ if (str[0] == '"') str++; @@ -4570,8 +5394,9 @@ decode_ussd_response (MMGenericGsm *self, if (p) *p = '\0'; - return mm_modem_gsm_ussd_decode (MM_MODEM_GSM_USSD (self), str, - cur_charset); + decoded = mm_modem_gsm_ussd_decode (MM_MODEM_GSM_USSD (self), str, cur_charset); + g_strfreev (items); + return decoded; } static char* @@ -4708,7 +5533,7 @@ ussd_send_done (MMAtSerialPort *port, ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE); } - /* Otherwise if no error wait for the response to show up via the + /* Otherwise if no error wait for the response to show up via the * unsolicited response code. */ } @@ -5150,10 +5975,20 @@ simple_status_got_signal_quality (MMModem *modem, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; GHashTable *properties; + gboolean error_no_network = FALSE; - if (!error) { + /* Treat "no network" as zero strength */ + if (g_error_matches (error, MM_MOBILE_ERROR, MM_MOBILE_ERROR_NO_NETWORK)) { + error_no_network = TRUE; + result = 0; + } + + if (!error || error_no_network) { properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG); g_hash_table_insert (properties, "signal_quality", simple_uint_value (result)); + } else { + g_clear_error (&info->error); + info->error = g_error_copy (error); } mm_callback_info_chain_complete_one (info); } @@ -5170,6 +6005,9 @@ simple_status_got_band (MMModem *modem, if (!error) { properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG); g_hash_table_insert (properties, "band", simple_uint_value (result)); + } else { + g_clear_error (&info->error); + info->error = g_error_copy (error); } mm_callback_info_chain_complete_one (info); } @@ -5189,9 +6027,10 @@ simple_status_got_reg_info (MMModemGsmNetwork *modem, if (!modem || mm_callback_info_check_modem_removed (info)) return; - if (error) + if (error) { + g_clear_error (&info->error); info->error = g_error_copy (error); - else { + } else { properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG); g_hash_table_insert (properties, "registration_status", simple_uint_value (status)); @@ -5503,6 +6342,8 @@ mm_generic_gsm_init (MMGenericGsm *self) priv->reg_regex = mm_gsm_creg_regex_get (TRUE); priv->roam_allowed = TRUE; priv->sms_present = g_hash_table_new (g_direct_hash, g_direct_equal); + priv->sms_contents = g_hash_table_new (g_direct_hash, g_direct_equal); + priv->sms_parts = g_hash_table_new (g_direct_hash, g_direct_equal); mm_properties_changed_signal_register_property (G_OBJECT (self), MM_MODEM_GSM_NETWORK_ALLOWED_MODE, @@ -5722,6 +6563,8 @@ finalize (GObject *object) g_free (priv->oper_name); g_free (priv->simid); g_hash_table_destroy (priv->sms_present); + g_hash_table_destroy (priv->sms_contents); + g_hash_table_destroy (priv->sms_parts); G_OBJECT_CLASS (mm_generic_gsm_parent_class)->finalize (object); } @@ -5841,4 +6684,3 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass) "+IFC=1,1", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } - diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index 4238628..8f6d587 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -84,7 +84,15 @@ typedef struct { * encountered during the process and the MMCallbackInfo created from the * callback and user_data passed in here. */ - void (*do_enable) (MMGenericGsm *self, MMModemFn callback, gpointer user_data); + void (*do_enable) (MMGenericGsm *self, + MMModemFn callback, + gpointer user_data); + + /* Called before issuing the power-up command, to check whether it should + * really be issued or not. */ + void (*do_enable_power_up_check_needed) (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data); /* Called after the generic class has attempted to power up the modem. * Subclasses can handle errors here if they know the device supports their @@ -137,6 +145,7 @@ typedef struct { void (*get_sim_iccid) (MMGenericGsm *self, MMModemStringFn callback, gpointer user_data); + } MMGenericGsmClass; GType mm_generic_gsm_get_type (void); diff --git a/src/mm-manager.c b/src/mm-manager.c index 1e9403c..41bed53 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -1101,5 +1101,6 @@ mm_manager_class_init (MMManagerClass *manager_class) dbus_g_error_domain_register (MM_MODEM_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_MODEM_ERROR); dbus_g_error_domain_register (MM_MODEM_CONNECT_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_MODEM_CONNECT_ERROR); dbus_g_error_domain_register (MM_MOBILE_ERROR, "org.freedesktop.ModemManager.Modem.Gsm", MM_TYPE_MOBILE_ERROR); + dbus_g_error_domain_register (MM_MSG_ERROR, "org.freedesktop.ModemManager.Modem.Gsm.SMS", MM_TYPE_MSG_ERROR); } diff --git a/src/mm-manager.h b/src/mm-manager.h index 1c98458..c6a64bd 100644 --- a/src/mm-manager.h +++ b/src/mm-manager.h @@ -17,7 +17,6 @@ #ifndef MM_MANAGER_H #define MM_MANAGER_H -#include #include #include #include "mm-modem.h" diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index 451e2eb..740dc13 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -480,9 +480,10 @@ info_item_done (MMCallbackInfo *info, const char *tag2, const char *desc) { - const char *p = response->str; + const char *p; if (!error) { + p = response->str; if (tag) p = mm_strip_tag (p, tag); if (tag2) diff --git a/src/mm-modem-base.h b/src/mm-modem-base.h index 0409957..d0cda3d 100644 --- a/src/mm-modem-base.h +++ b/src/mm-modem-base.h @@ -18,7 +18,6 @@ #define MM_MODEM_BASE_H #include -#include #include #include "mm-port.h" diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c index 485e5f2..7583760 100644 --- a/src/mm-modem-cdma.c +++ b/src/mm-modem-cdma.c @@ -131,6 +131,8 @@ serving_system_call_done (MMModemCdma *self, g_value_unset (&value); dbus_g_method_return (context, array); + + g_value_array_free (array); } } diff --git a/src/mm-modem-gsm-network.c b/src/mm-modem-gsm-network.c index c152ddf..6748b4e 100644 --- a/src/mm-modem-gsm-network.c +++ b/src/mm-modem-gsm-network.c @@ -202,6 +202,8 @@ reg_info_call_done (MMModemGsmNetwork *self, g_value_unset (&value); dbus_g_method_return (context, array); + + g_value_array_free (array); } } diff --git a/src/mm-modem-gsm-sms.c b/src/mm-modem-gsm-sms.c index ab20d3e..22c42d0 100644 --- a/src/mm-modem-gsm-sms.c +++ b/src/mm-modem-gsm-sms.c @@ -133,6 +133,14 @@ sms_list_done (MMModemGsmSms *self, /*****************************************************************************/ +static void +sms_send_invoke (MMCallbackInfo *info) +{ + MMModemGsmSmsSendFn callback = (MMModemGsmSmsSendFn) info->callback; + + callback (MM_MODEM_GSM_SMS (info->modem), NULL, info->error, info->user_data); +} + void mm_modem_gsm_sms_send (MMModemGsmSms *self, const char *number, @@ -140,7 +148,7 @@ mm_modem_gsm_sms_send (MMModemGsmSms *self, const char *smsc, guint validity, guint class, - MMModemFn callback, + MMModemGsmSmsSendFn callback, gpointer user_data) { g_return_if_fail (MM_IS_MODEM_GSM_SMS (self)); @@ -150,9 +158,18 @@ mm_modem_gsm_sms_send (MMModemGsmSms *self, if (MM_MODEM_GSM_SMS_GET_INTERFACE (self)->send) MM_MODEM_GSM_SMS_GET_INTERFACE (self)->send (self, number, text, smsc, validity, class, callback, user_data); - else - async_call_not_supported (self, callback, user_data); + else { + MMCallbackInfo *info; + + info = mm_callback_info_new_full (MM_MODEM (self), + sms_send_invoke, + G_CALLBACK (callback), + user_data); + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, + "Operation not supported"); + mm_callback_info_schedule (info); + } } static void @@ -575,6 +592,20 @@ impl_gsm_modem_sms_save (MMModemGsmSms *modem, /*****************************************************************************/ +static void +send_sms_call_done (MMModemGsmSms *modem, + GArray *indexes, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context, indexes); +} + static void sms_send_auth_cb (MMAuthRequest *req, GObject *owner, @@ -607,7 +638,7 @@ sms_send_auth_cb (MMAuthRequest *req, if (value) smsc = g_value_get_string (value); - value = (GValue *) g_hash_table_lookup (info->hash, "validity"); + value = (GValue *) g_hash_table_lookup (info->hash, "relative-validity"); if (value) validity = g_value_get_uint (value); @@ -625,10 +656,10 @@ sms_send_auth_cb (MMAuthRequest *req, done: if (error) { - async_call_done (MM_MODEM (self), error, context); + send_sms_call_done (self, NULL, error, context); g_error_free (error); } else - mm_modem_gsm_sms_send (self, number, text, smsc, validity, class, async_call_done, context); + mm_modem_gsm_sms_send (self, number, text, smsc, validity, class, send_sms_call_done, context); } static void diff --git a/src/mm-modem-gsm-sms.h b/src/mm-modem-gsm-sms.h index 41684d7..11a1024 100644 --- a/src/mm-modem-gsm-sms.h +++ b/src/mm-modem-gsm-sms.h @@ -35,6 +35,11 @@ typedef void (*MMModemGsmSmsListFn) (MMModemGsmSms *modem, GError *error, gpointer user_data); +typedef void (*MMModemGsmSmsSendFn) (MMModemGsmSms *modem, + GArray *indexes, + GError *error, + gpointer user_data); + struct _MMModemGsmSms { GTypeInterface g_iface; @@ -45,7 +50,7 @@ struct _MMModemGsmSms { const char *smsc, guint validity, guint class, - MMModemFn callback, + MMModemGsmSmsSendFn callback, gpointer user_data); void (*get) (MMModemGsmSms *modem, @@ -80,7 +85,7 @@ void mm_modem_gsm_sms_send (MMModemGsmSms *self, const char *smsc, guint validity, guint class, - MMModemFn callback, + MMModemGsmSmsSendFn callback, gpointer user_data); void mm_modem_gsm_sms_get (MMModemGsmSms *self, diff --git a/src/mm-modem-gsm-ussd.h b/src/mm-modem-gsm-ussd.h index 04d2be8..f46be97 100644 --- a/src/mm-modem-gsm-ussd.h +++ b/src/mm-modem-gsm-ussd.h @@ -81,8 +81,8 @@ void mm_modem_gsm_ussd_cancel (MMModemGsmUssd *self, gpointer user_data); /* CBS data coding scheme - 3GPP TS 23.038 */ -#define MM_MODEM_GSM_USSD_SCHEME_7BIT 0b00001111; -#define MM_MODEM_GSM_USSD_SCHEME_UCS2 0b01001000; +#define MM_MODEM_GSM_USSD_SCHEME_7BIT 0b00001111 +#define MM_MODEM_GSM_USSD_SCHEME_UCS2 0b01001000 char *mm_modem_gsm_ussd_encode (MMModemGsmUssd *self, const char* command, diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index f6a0ffa..5291ed5 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -11,7 +11,7 @@ * GNU General Public License for more details: * * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. */ #include @@ -112,9 +112,9 @@ mm_gsm_parse_scan_response (const char *reply, GError **error) * +COPS: (2,"","T-Mobile","31026",0),(1,"AT&T","AT&T","310410"),0) */ - r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^,\\)]*)[\\)]?,(\\d)\\)", G_REGEX_UNGREEDY, 0, NULL); + r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^,\\)]*)[\\)]?,(\\d)\\)", G_REGEX_UNGREEDY, 0, &err); if (err) { - g_error ("Invalid regular expression: %s", err->message); + mm_err ("Invalid regular expression: %s", err->message); g_error_free (err); g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, @@ -125,10 +125,8 @@ mm_gsm_parse_scan_response (const char *reply, GError **error) /* If we didn't get any hits, try the pre-UMTS format match */ if (!g_regex_match (r, reply, 0, &match_info)) { g_regex_unref (r); - if (match_info) { - g_match_info_free (match_info); - match_info = NULL; - } + g_match_info_free (match_info); + match_info = NULL; /* Pre-UMTS format doesn't include the cell access technology after * the numeric operator element. @@ -143,9 +141,9 @@ mm_gsm_parse_scan_response (const char *reply, GError **error) * +COPS: (2,"T - Mobile",,"31026"),(1,"Einstein PCS",,"31064"),(1,"Cingular",,"31041"),,(0,1,3),(0,2) */ - r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^\\)]*)\\)", G_REGEX_UNGREEDY, 0, NULL); + r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^\\)]*)\\)", G_REGEX_UNGREEDY, 0, &err); if (err) { - g_error ("Invalid regular expression: %s", err->message); + mm_err ("Invalid regular expression: %s", err->message); g_error_free (err); g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, @@ -247,6 +245,9 @@ mm_gsm_destroy_scan_data (gpointer data) /* '+CREG: 2,1,000B,2816, B, C2816OK' */ #define CREG7 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*" +/* +CREG: ,,,, (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */ +#define CREG8 "\\+(CREG|CGREG):\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})\\s*,\\s*([^,\\s]*)" + GPtrArray * mm_gsm_creg_regex_get (gboolean solicited) { @@ -309,6 +310,14 @@ mm_gsm_creg_regex_get (gboolean solicited) g_assert (regex); g_ptr_array_add (array, regex); + /* #8 */ + if (solicited) + regex = g_regex_new (CREG8 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG8 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + return array; } @@ -346,6 +355,20 @@ parse_uint (char *str, int base, glong nmin, glong nmax, gboolean *valid) return *valid ? (guint) ret : 0; } +static gboolean +item_is_lac_not_stat (GMatchInfo *info, guint32 item) +{ + char *str; + gboolean is_lac = FALSE; + + /* A will always be a single digit, without quotes */ + str = g_match_info_fetch (info, item); + g_assert (str); + is_lac = (strchr (str, '"') || strlen (str) > 1); + g_free (str); + return is_lac; +} + gboolean mm_gsm_parse_creg_response (GMatchInfo *info, guint32 *out_reg_state, @@ -371,6 +394,7 @@ mm_gsm_parse_creg_response (GMatchInfo *info, str = g_match_info_fetch (info, 1); if (str && strstr (str, "CGREG")) *out_cgreg = TRUE; + g_free (str); /* Normally the number of matches could be used to determine what each * item is, but we have overlap in one case. @@ -392,13 +416,8 @@ mm_gsm_parse_creg_response (GMatchInfo *info, * CREG=2 (non-standard): +CREG: ,,, */ - /* To distinguish, check length of the third match item. If it's - * more than one digit or has quotes in it then it's a LAC and we - * got the first format. - */ - str = g_match_info_fetch (info, 3); - if (str && (strchr (str, '"') || strlen (str) > 1)) { - g_free (str); + /* Check if the third item is the LAC to distinguish the two cases */ + if (item_is_lac_not_stat (info, 3)) { istat = 2; ilac = 3; ici = 4; @@ -409,12 +428,23 @@ mm_gsm_parse_creg_response (GMatchInfo *info, ici = 5; } } else if (n_matches == 7) { - /* CREG=2 (non-standard): +CREG: ,,,, */ - istat = 3; - ilac = 4; - ici = 5; - iact = 6; - } + /* CREG=2 (solicited): +CREG: ,,,, + * CREG=2 (unsolicited with RAC): +CREG: ,,,, + */ + + /* Check if the third item is the LAC to distinguish the two cases */ + if (item_is_lac_not_stat (info, 3)) { + istat = 2; + ilac = 3; + ici = 4; + iact = 5; + } else { + istat = 3; + ilac = 4; + ici = 5; + iact = 6; + } + } /* Status */ str = g_match_info_fetch (info, istat); @@ -778,8 +808,8 @@ mm_gsm_parse_cscs_support_response (const char *reply, g_match_info_next (match_info, NULL); success = TRUE; } - g_match_info_free (match_info); } + g_match_info_free (match_info); g_regex_unref (r); if (success) @@ -855,8 +885,10 @@ mm_create_device_identifier (guint vid, if (manf) g_string_append (devid, manf); - if (!strlen (devid->str)) + if (!strlen (devid->str)) { + g_string_free (devid, TRUE); return NULL; + } p = devid->str; msg = g_string_sized_new (strlen (devid->str) + 17); @@ -888,6 +920,7 @@ mm_create_device_identifier (guint vid, mm_dbg ("Device ID source '%s'", msg->str); mm_dbg ("Device ID '%s'", ret); g_string_free (msg, TRUE); + g_string_free (devid, TRUE); return ret; } @@ -1020,8 +1053,8 @@ mm_parse_cind_test_response (const char *reply, GError **error) g_match_info_next (match_info, NULL); } - g_match_info_free (match_info); } + g_match_info_free (match_info); g_regex_unref (r); return hash; @@ -1086,11 +1119,10 @@ mm_parse_cind_query_response(const char *reply, GError **error) g_free (str); g_match_info_next (match_info, NULL); } - g_match_info_free (match_info); done: - if (r) - g_regex_unref (r); + g_match_info_free (match_info); + g_regex_unref (r); return array; } diff --git a/src/mm-modem.c b/src/mm-modem.c index b3c1677..33b8116 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -323,6 +323,8 @@ get_ip4_done (MMModem *modem, value_array_add_uint (array, dns3); dbus_g_method_return (context, array); + + g_value_array_free (array); } } @@ -411,6 +413,8 @@ info_call_done (MMModem *self, g_value_unset (&value); dbus_g_method_return (context, array); + + g_value_array_free (array); } } diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index 0777021..5248181 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -36,6 +36,7 @@ #include "mm-utils.h" #include "libqcdm/src/commands.h" #include "libqcdm/src/utils.h" +#include "libqcdm/src/errors.h" #include "mm-log.h" static void plugin_init (MMPlugin *plugin_class); @@ -403,6 +404,11 @@ static const char *dq_strings[] = { NULL }; +static guint8 zerobuf[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + static void port_buffer_full (MMSerialPort *port, GByteArray *buffer, gpointer user_data) { @@ -412,6 +418,13 @@ port_buffer_full (MMSerialPort *port, GByteArray *buffer, gpointer user_data) size_t iter_len; int i; + /* Some devices (observed on a ZTE branded "QUALCOMM INCORPORATED" model + * "154") spew NULLs from some ports. + */ + if ( (buffer->len >= sizeof (zerobuf)) + && (memcmp (buffer->data, zerobuf, sizeof (zerobuf)) == 0)) + goto stop_probing; + /* Check for an immediate disqualification response. There are some * ports (Option Icera-based chipsets have them, as do Qualcomm Gobi * devices before their firmware is loaded) that just shouldn't be @@ -428,13 +441,16 @@ port_buffer_full (MMSerialPort *port, GByteArray *buffer, gpointer user_data) for (i = 0; i < buffer->len - iter_len; i++) { if (!memcmp (&buffer->data[i], *iter, iter_len)) { /* Immediately close the port and complete probing */ - priv->probed_caps = 0; - mm_serial_port_close (MM_SERIAL_PORT (priv->probe_port)); - probe_complete (task); - return; + goto stop_probing; } } } + return; + +stop_probing: + priv->probed_caps = 0; + mm_serial_port_close (MM_SERIAL_PORT (priv->probe_port)); + probe_complete (task); } static gboolean @@ -482,8 +498,8 @@ qcdm_verinfo_cb (MMQcdmSerialPort *port, { MMPluginBaseSupportsTask *task; MMPluginBaseSupportsTaskPrivate *priv; - QCDMResult *result; - GError *dm_error = NULL; + QcdmResult *result; + int err = QCDM_SUCCESS; /* Just the initial poke; ignore it */ if (!user_data) @@ -498,13 +514,10 @@ qcdm_verinfo_cb (MMQcdmSerialPort *port, } /* Parse the response */ - result = qcdm_cmd_version_info_result ((const char *) response->data, response->len, &dm_error); + result = qcdm_cmd_version_info_result ((const char *) response->data, response->len, &err); if (!result) { - g_warning ("(%s) failed to parse QCDM version info command result: (%d) %s.", - g_udev_device_get_name (priv->port), - dm_error ? dm_error->code : -1, - dm_error && dm_error->message ? dm_error->message : "(unknown)"); - g_clear_error (&dm_error); + g_warning ("(%s) failed to parse QCDM version info command result: %d", + g_udev_device_get_name (priv->port), err); goto done; } @@ -554,14 +567,10 @@ try_qcdm_probe (MMPluginBaseSupportsTask *task) /* Build up the probe command */ verinfo = g_byte_array_sized_new (50); - len = qcdm_cmd_version_info_new ((char *) verinfo->data, 50, &error); + len = qcdm_cmd_version_info_new ((char *) verinfo->data, 50); if (len <= 0) { g_byte_array_free (verinfo, TRUE); - g_warning ("(%s) failed to create QCDM version info command: (%d) %s.", - name, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); + g_warning ("(%s) failed to create QCDM version info command", name); probe_complete (task); return; } diff --git a/src/mm-plugin-base.h b/src/mm-plugin-base.h index 799f681..e69ad17 100644 --- a/src/mm-plugin-base.h +++ b/src/mm-plugin-base.h @@ -17,7 +17,6 @@ #define MM_PLUGIN_BASE_H #include -#include #include #define G_UDEV_API_IS_SUBJECT_TO_CHANGE diff --git a/src/mm-port.h b/src/mm-port.h index 4bcffd4..df935db 100644 --- a/src/mm-port.h +++ b/src/mm-port.h @@ -17,7 +17,6 @@ #define MM_PORT_H #include -#include #include typedef enum { diff --git a/src/mm-qcdm-serial-port.c b/src/mm-qcdm-serial-port.c index e467f2a..0d763bf 100644 --- a/src/mm-qcdm-serial-port.c +++ b/src/mm-qcdm-serial-port.c @@ -23,6 +23,7 @@ #include "mm-errors.h" #include "libqcdm/src/com.h" #include "libqcdm/src/utils.h" +#include "libqcdm/src/errors.h" #include "mm-log.h" G_DEFINE_TYPE (MMQcdmSerialPort, mm_qcdm_serial_port, MM_TYPE_SERIAL_PORT) @@ -81,7 +82,8 @@ handle_response (MMSerialPort *port, GError *dm_error = NULL; gsize used = 0; gsize start = 0; - gboolean success = FALSE, more = FALSE; + gboolean success = FALSE; + qcdmbool more = FALSE; gsize unescaped_len = 0; if (error) @@ -200,7 +202,15 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len) static gboolean config_fd (MMSerialPort *port, int fd, GError **error) { - return qcdm_port_setup (fd, error); + int err; + + err = qcdm_port_setup (fd); + if (err != QCDM_SUCCESS) { + g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, + "Failed to open QCDM port: %d", err); + return FALSE; + } + return TRUE; } /*****************************************************************************/ diff --git a/src/mm-qcdm-serial-port.h b/src/mm-qcdm-serial-port.h index 2786ee8..605016d 100644 --- a/src/mm-qcdm-serial-port.h +++ b/src/mm-qcdm-serial-port.h @@ -18,7 +18,6 @@ #define MM_QCDM_SERIAL_PORT_H #include -#include #include #include "mm-serial-port.h" diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c index 344e1bc..4212e19 100644 --- a/src/mm-serial-parsers.c +++ b/src/mm-serial-parsers.c @@ -82,6 +82,7 @@ remove_matches (GRegex *r, GString *string) typedef struct { GRegex *generic_response; GRegex *detailed_error; + GRegex *cms_error; } MMSerialParserV0; gpointer @@ -94,6 +95,7 @@ mm_serial_parser_v0_new (void) parser->generic_response = g_regex_new ("(\\d)\\0?\\r$", flags, 0, NULL); parser->detailed_error = g_regex_new ("\\+CME ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); + parser->cms_error = g_regex_new ("\\+CMS ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); return parser; } @@ -125,8 +127,6 @@ mm_serial_parser_v0_parse (gpointer data, } else code = MM_MOBILE_ERROR_UNKNOWN; - g_match_info_free (match_info); - switch (code) { case 0: /* OK */ break; @@ -155,9 +155,10 @@ mm_serial_parser_v0_parse (gpointer data, remove_matches (parser->generic_response, response); } + g_match_info_free (match_info); + if (!found) { found = g_regex_match_full (parser->detailed_error, response->str, response->len, 0, 0, &match_info, NULL); - if (found) { str = g_match_info_fetch (match_info, 1); if (str) { @@ -166,9 +167,24 @@ mm_serial_parser_v0_parse (gpointer data, } else code = MM_MOBILE_ERROR_UNKNOWN; - g_match_info_free (match_info); local_error = mm_mobile_error_for_code (code); } + g_match_info_free (match_info); + + if (!found) { + found = g_regex_match_full (parser->cms_error, response->str, response->len, 0, 0, &match_info, NULL); + if (found) { + str = g_match_info_fetch (match_info, 1); + if (str) { + code = atoi (str); + g_free (str); + } else + code = MM_MSG_ERROR_UNKNOWN; + + local_error = mm_msg_error_for_code (code); + } + g_match_info_free (match_info); + } } if (found) @@ -191,6 +207,7 @@ mm_serial_parser_v0_destroy (gpointer data) g_regex_unref (parser->generic_response); g_regex_unref (parser->detailed_error); + g_regex_unref (parser->cms_error); g_slice_free (MMSerialParserV0, data); } @@ -204,6 +221,7 @@ typedef struct { GRegex *regex_cme_error; GRegex *regex_cms_error; GRegex *regex_cme_error_str; + GRegex *regex_cms_error_str; GRegex *regex_ezx_error; GRegex *regex_unknown_error; GRegex *regex_connect_failed; @@ -223,6 +241,7 @@ mm_serial_parser_v1_new (void) parser->regex_cme_error = g_regex_new ("\\r\\n\\+CME ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); parser->regex_cms_error = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); parser->regex_cme_error_str = g_regex_new ("\\r\\n\\+CME ERROR:\\s*([^\\n\\r]+)\\r\\n$", flags, 0, NULL); + parser->regex_cms_error_str = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*([^\\n\\r]+)\\r\\n$", flags, 0, NULL); parser->regex_ezx_error = g_regex_new ("\\r\\n\\MODEM ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); parser->regex_unknown_error = g_regex_new ("\\r\\n(ERROR)|(COMMAND NOT SUPPORT)\\r\\n$", flags, 0, NULL); parser->regex_connect_failed = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n$", flags, 0, NULL); @@ -260,13 +279,17 @@ mm_serial_parser_v1_parse (gpointer data, GMatchInfo *match_info; GError *local_error = NULL; gboolean found = FALSE; - char *str; + char *str = NULL; int code; g_return_val_if_fail (parser != NULL, FALSE); g_return_val_if_fail (response != NULL, FALSE); - if (G_UNLIKELY (!response->len || !strlen (response->str))) + /* Skip NUL bytes if they are found leading the response */ + while (response->len > 0 && response->str[0] == '\0') + g_string_erase (response, 0, 1); + + if (G_UNLIKELY (!response->len)) return FALSE; /* First, check for successful responses */ @@ -306,10 +329,9 @@ mm_serial_parser_v1_parse (gpointer data, str = g_match_info_fetch (match_info, 1); g_assert (str); local_error = mm_mobile_error_for_code (atoi (str)); - g_free (str); - g_match_info_free (match_info); goto done; } + g_match_info_free (match_info); } /* Numeric CME errors */ @@ -320,27 +342,21 @@ mm_serial_parser_v1_parse (gpointer data, str = g_match_info_fetch (match_info, 1); g_assert (str); local_error = mm_mobile_error_for_code (atoi (str)); - g_free (str); - g_match_info_free (match_info); goto done; } + g_match_info_free (match_info); /* Numeric CMS errors */ - /* Todo - * One should probably add message service - * errors explicitly in mm-errors.h/c - */ found = g_regex_match_full (parser->regex_cms_error, response->str, response->len, 0, 0, &match_info, NULL); if (found) { str = g_match_info_fetch (match_info, 1); g_assert (str); - local_error = mm_mobile_error_for_code (atoi (str)); - g_free (str); - g_match_info_free (match_info); + local_error = mm_msg_error_for_code (atoi (str)); goto done; } + g_match_info_free (match_info); /* String CME errors */ found = g_regex_match_full (parser->regex_cme_error_str, @@ -350,10 +366,21 @@ mm_serial_parser_v1_parse (gpointer data, str = g_match_info_fetch (match_info, 1); g_assert (str); local_error = mm_mobile_error_for_string (str); - g_free (str); - g_match_info_free (match_info); goto done; } + g_match_info_free (match_info); + + /* String CMS errors */ + found = g_regex_match_full (parser->regex_cms_error_str, + response->str, response->len, + 0, 0, &match_info, NULL); + if (found) { + str = g_match_info_fetch (match_info, 1); + g_assert (str); + local_error = mm_msg_error_for_string (str); + goto done; + } + g_match_info_free (match_info); /* Motorola EZX errors */ found = g_regex_match_full (parser->regex_ezx_error, @@ -363,19 +390,19 @@ mm_serial_parser_v1_parse (gpointer data, str = g_match_info_fetch (match_info, 1); g_assert (str); local_error = mm_mobile_error_for_code (MM_MOBILE_ERROR_UNKNOWN); - g_free (str); - g_match_info_free (match_info); goto done; } + g_match_info_free (match_info); /* Last resort; unknown error */ found = g_regex_match_full (parser->regex_unknown_error, response->str, response->len, - 0, 0, NULL, NULL); + 0, 0, &match_info, NULL); if (found) { local_error = mm_mobile_error_for_code (MM_MOBILE_ERROR_UNKNOWN); goto done; } + g_match_info_free (match_info); /* Connection failures */ found = g_regex_match_full (parser->regex_connect_failed, @@ -398,13 +425,12 @@ mm_serial_parser_v1_parse (gpointer data, code = MM_MODEM_CONNECT_ERROR_NO_CARRIER; } - g_free (str); - g_match_info_free (match_info); - local_error = mm_modem_connect_error_for_code (code); } done: + g_free (str); + g_match_info_free (match_info); if (found) response_clean (response); @@ -426,7 +452,9 @@ mm_serial_parser_v1_destroy (gpointer data) g_regex_unref (parser->regex_ok); g_regex_unref (parser->regex_connect); g_regex_unref (parser->regex_cme_error); + g_regex_unref (parser->regex_cms_error); g_regex_unref (parser->regex_cme_error_str); + g_regex_unref (parser->regex_cms_error_str); g_regex_unref (parser->regex_ezx_error); g_regex_unref (parser->regex_unknown_error); g_regex_unref (parser->regex_connect_failed); diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 46050cf..b7b5a73 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -958,6 +958,15 @@ internal_queue_command (MMSerialPort *self, g_return_if_fail (MM_IS_SERIAL_PORT (self)); g_return_if_fail (command != NULL); + if (priv->open_count == 0) { + GError *error = g_error_new_literal (MM_SERIAL_ERROR, + MM_SERIAL_ERROR_SEND_FAILED, + "Sending command failed: device is not enabled"); + callback (self, NULL, error, user_data); + g_error_free (error); + return; + } + info = g_slice_new0 (MMQueueData); if (take_command) info->command = command; @@ -1290,7 +1299,11 @@ set_property (GObject *object, guint prop_id, priv->bits = g_value_get_uint (value); break; case PROP_PARITY: +#if GLIB_CHECK_VERSION(2,31,0) + priv->parity = g_value_get_schar (value); +#else priv->parity = g_value_get_char (value); +#endif break; case PROP_STOPBITS: priv->stopbits = g_value_get_uint (value); @@ -1327,7 +1340,11 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->bits); break; case PROP_PARITY: +#if GLIB_CHECK_VERSION(2,31,0) + g_value_set_schar (value, priv->parity); +#else g_value_set_char (value, priv->parity); +#endif break; case PROP_STOPBITS: g_value_set_uint (value, priv->stopbits); diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h index ae38017..f988af3 100644 --- a/src/mm-serial-port.h +++ b/src/mm-serial-port.h @@ -18,7 +18,6 @@ #define MM_SERIAL_PORT_H #include -#include #include #include "mm-port.h" diff --git a/src/mm-sms-utils.c b/src/mm-sms-utils.c index 3f56a64..4e52ec4 100644 --- a/src/mm-sms-utils.c +++ b/src/mm-sms-utils.c @@ -13,12 +13,17 @@ * Copyright (C) 2011 Red Hat, Inc. */ +#include +#include + #include #include "mm-charsets.h" #include "mm-errors.h" #include "mm-utils.h" #include "mm-sms-utils.h" +#include "mm-log.h" +#include "dbus/dbus-glib.h" #define SMS_TP_MTI_MASK 0x03 #define SMS_TP_MTI_SMS_DELIVER 0x00 @@ -70,6 +75,93 @@ sms_semi_octets_to_bcd_string (char *dest, const guint8 *octets, int num_octets) *dest++ = '\0'; } +static gboolean +char_to_bcd (char in, guint8 *out) +{ + guint32 z; + + if (isdigit (in)) { + *out = in - 0x30; + return TRUE; + } + + for (z = 10; z < 16; z++) { + if (in == sms_bcd_chars[z]) { + *out = z; + return TRUE; + } + } + return FALSE; +} + +static gsize +sms_string_to_bcd_semi_octets (guint8 *buf, gsize buflen, const char *string) +{ + guint i; + guint8 bcd; + gsize addrlen, slen; + + addrlen = slen = strlen (string); + if (addrlen % 2) + addrlen++; + g_return_val_if_fail (buflen >= addrlen, 0); + + for (i = 0; i < addrlen; i += 2) { + if (!char_to_bcd (string[i], &bcd)) + return 0; + buf[i / 2] = bcd & 0xF; + + if (i >= slen - 1) { + /* PDU address gets padded with 0xF if string is odd length */ + bcd = 0xF; + } else if (!char_to_bcd (string[i + 1], &bcd)) + return 0; + buf[i / 2] |= bcd << 4; + } + return addrlen / 2; +} + +/** + * sms_encode_address: + * + * @address: the phone number to encode + * @buf: the buffer to encode @address in + * @buflen: the size of @buf + * @is_smsc: if %TRUE encode size as number of octets of address infromation, + * otherwise if %FALSE encode size as number of digits of @address + * + * Returns: the size in bytes of the data added to @buf + **/ +guint +sms_encode_address (const char *address, + guint8 *buf, + size_t buflen, + gboolean is_smsc) +{ + gsize len; + + g_return_val_if_fail (address != NULL, 0); + g_return_val_if_fail (buf != NULL, 0); + g_return_val_if_fail (buflen >= 2, 0); + + /* Handle number type & plan */ + buf[1] = 0x80; /* Bit 7 always 1 */ + if (address[0] == '+') { + buf[1] |= SMS_NUMBER_TYPE_INTL; + address++; + } + buf[1] |= SMS_NUMBER_PLAN_TELEPHONE; + + len = sms_string_to_bcd_semi_octets (&buf[2], buflen, address); + + if (is_smsc) + buf[0] = len + 1; /* addr length + size byte */ + else + buf[0] = strlen (address); /* number of digits in address */ + + return len ? len + 2 : 0; /* addr length + size byte + number type/plan */ +} + /* len is in semi-octets */ static char * sms_decode_address (const guint8 *address, int len) @@ -200,10 +292,10 @@ sms_decode_text (const guint8 *text, int len, SmsEncoding encoding, int bit_offs g_free (unpacked); } else if (encoding == MM_SMS_ENCODING_UCS2) utf8 = g_convert ((char *) text, len, "UTF8", "UCS-2BE", NULL, NULL, NULL); - else if (encoding == MM_SMS_ENCODING_8BIT) - utf8 = g_strndup ((const char *)text, len); - else + else { + g_warn_if_reached (); utf8 = g_strdup (""); + } return utf8; } @@ -230,48 +322,83 @@ simple_uint_value (guint32 i) } static GValue * -simple_boolean_value (gboolean b) +simple_string_value (const char *str) { GValue *val; val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_BOOLEAN); - g_value_set_boolean (val, b); + g_value_init (val, G_TYPE_STRING); + g_value_set_string (val, str); return val; } static GValue * -simple_string_value (const char *str) +byte_array_value (const GByteArray *array) { GValue *val; val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, str); + g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY); + g_value_set_boxed (val, array); return val; } +GHashTable * +sms_properties_hash_new (const char *smsc, + const char *number, + const char *timestamp, + const char *text, + const GByteArray *data, + guint data_coding_scheme, + guint *class) +{ + GHashTable *properties; + + g_return_val_if_fail (number != NULL, NULL); + g_return_val_if_fail (text != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); + + properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, simple_free_gvalue); + g_hash_table_insert (properties, "number", simple_string_value (number)); + g_hash_table_insert (properties, "data", byte_array_value (data)); + g_hash_table_insert (properties, "data-coding-scheme", simple_uint_value (data_coding_scheme)); + g_hash_table_insert (properties, "text", simple_string_value (text)); + + if (smsc) + g_hash_table_insert (properties, "smsc", simple_string_value (smsc)); + + if (timestamp) + g_hash_table_insert (properties, "timestamp", simple_string_value (timestamp)); + + if (class) + g_hash_table_insert (properties, "class", simple_uint_value (*class)); + + return properties; +} + GHashTable * sms_parse_pdu (const char *hexpdu, GError **error) { GHashTable *properties; gsize pdu_len; guint8 *pdu; - int smsc_addr_num_octets, variable_length_items, msg_start_offset, + guint smsc_addr_num_octets, variable_length_items, msg_start_offset, sender_addr_num_digits, sender_addr_num_octets, tp_pid_offset, tp_dcs_offset, user_data_offset, user_data_len, user_data_len_offset, bit_offset; char *smsc_addr, *sender_addr, *sc_timestamp, *msg_text; SmsEncoding user_data_encoding; + GByteArray *pdu_data; + guint concat_ref = 0, concat_max = 0, concat_seq = 0, msg_class = 0; + gboolean multipart = FALSE, class_valid = FALSE; /* Convert PDU from hex to binary */ pdu = (guint8 *) utils_hexstr2bin (hexpdu, &pdu_len); if (!pdu) { - *error = g_error_new_literal (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "Couldn't parse PDU of SMS GET response from hex"); + g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Couldn't parse PDU of SMS GET response from hex"); return NULL; } @@ -279,10 +406,10 @@ sms_parse_pdu (const char *hexpdu, GError **error) smsc_addr_num_octets = pdu[0]; variable_length_items = smsc_addr_num_octets; if (pdu_len < variable_length_items + SMS_MIN_PDU_LEN) { - *error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "PDU too short (1): %zd vs %d", pdu_len, - variable_length_items + SMS_MIN_PDU_LEN); + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "PDU too short (1): %zd vs %d", + pdu_len, + variable_length_items + SMS_MIN_PDU_LEN); g_free (pdu); return NULL; } @@ -297,10 +424,10 @@ sms_parse_pdu (const char *hexpdu, GError **error) sender_addr_num_octets = (sender_addr_num_digits + 1) >> 1; variable_length_items += sender_addr_num_octets; if (pdu_len < variable_length_items + SMS_MIN_PDU_LEN) { - *error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "PDU too short (2): %zd vs %d", pdu_len, - variable_length_items + SMS_MIN_PDU_LEN); + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "PDU too short (2): %zd vs %d", + pdu_len, + variable_length_items + SMS_MIN_PDU_LEN); g_free (pdu); return NULL; } @@ -317,36 +444,71 @@ sms_parse_pdu (const char *hexpdu, GError **error) else variable_length_items += user_data_len; if (pdu_len < variable_length_items + SMS_MIN_PDU_LEN) { - *error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "PDU too short (3): %zd vs %d", pdu_len, - variable_length_items + SMS_MIN_PDU_LEN); + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "PDU too short (3): %zd vs %d", + pdu_len, + variable_length_items + SMS_MIN_PDU_LEN); g_free (pdu); return NULL; } /* Only handle SMS-DELIVER */ if ((pdu[msg_start_offset] & SMS_TP_MTI_MASK) != SMS_TP_MTI_SMS_DELIVER) { - *error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "Unhandled message type: 0x%02x", - pdu[msg_start_offset]); + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Unhandled message type: 0x%02x", + pdu[msg_start_offset]); g_free (pdu); return NULL; } - smsc_addr = sms_decode_address (&pdu[1], 2 * (pdu[0] - 1)); - sender_addr = sms_decode_address (&pdu[msg_start_offset + 2], - pdu[msg_start_offset + 1]); - sc_timestamp = sms_decode_timestamp (&pdu[tp_dcs_offset + 1]); bit_offset = 0; if (pdu[msg_start_offset] & SMS_TP_UDHI) { + int udhl, end, offset; + udhl = pdu[user_data_offset] + 1; + end = user_data_offset + udhl; + + for (offset = user_data_offset + 1; offset < end;) { + guint8 ie_id, ie_len; + + ie_id = pdu[offset++]; + ie_len = pdu[offset++]; + + switch (ie_id) { + case 0x00: + /* + * Ignore the IE if one of the following is true: + * - it claims to be part 0 of M + * - it claims to be part N of M, N > M + */ + if (pdu[offset + 2] == 0 || + pdu[offset + 2] > pdu[offset + 1]) + break; + + concat_ref = pdu[offset]; + concat_max = pdu[offset + 1]; + concat_seq = pdu[offset + 2]; + multipart = TRUE; + break; + case 0x08: + /* Concatenated short message, 16-bit reference */ + if (pdu[offset + 3] == 0 || + pdu[offset + 3] > pdu[offset + 2]) + break; + + concat_ref = (pdu[offset] << 8) | pdu[offset + 1]; + concat_max = pdu[offset + 2]; + concat_seq = pdu[offset + 3]; + multipart = TRUE; + break; + } + + offset += ie_len; + } + /* - * Skip over the user data headers to prevent it from being + * Move past the user data headers to prevent it from being * decoded into garbage text. */ - int udhl; - udhl = pdu[user_data_offset] + 1; user_data_offset += udhl; if (user_data_encoding == MM_SMS_ENCODING_GSM7) { /* @@ -359,31 +521,274 @@ sms_parse_pdu (const char *hexpdu, GError **error) user_data_len -= udhl; } - msg_text = sms_decode_text (&pdu[user_data_offset], user_data_len, - user_data_encoding, bit_offset); - - properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - simple_free_gvalue); - g_hash_table_insert (properties, "number", - simple_string_value (sender_addr)); - g_hash_table_insert (properties, "text", - simple_string_value (msg_text)); - g_hash_table_insert (properties, "smsc", - simple_string_value (smsc_addr)); - g_hash_table_insert (properties, "timestamp", - simple_string_value (sc_timestamp)); - if (pdu[tp_dcs_offset] & SMS_DCS_CLASS_VALID) - g_hash_table_insert (properties, "class", - simple_uint_value (pdu[tp_dcs_offset] & - SMS_DCS_CLASS_MASK)); - g_hash_table_insert (properties, "completed", simple_boolean_value (TRUE)); + if ( user_data_encoding == MM_SMS_ENCODING_8BIT + || user_data_encoding == MM_SMS_ENCODING_UNKNOWN) { + /* 8-bit encoding is usually binary data, and we have no idea what + * actual encoding the data is in so we can't convert it. + */ + msg_text = g_strdup (""); + } else { + /* Otherwise if it's 7-bit or UCS2 we can decode it */ + msg_text = sms_decode_text (&pdu[user_data_offset], user_data_len, + user_data_encoding, bit_offset); + g_warn_if_fail (msg_text != NULL); + } + + /* Raw PDU data */ + pdu_data = g_byte_array_sized_new (user_data_len); + g_byte_array_append (pdu_data, &pdu[user_data_offset], user_data_len); + + if (pdu[tp_dcs_offset] & SMS_DCS_CLASS_VALID) { + msg_class = pdu[tp_dcs_offset] & SMS_DCS_CLASS_MASK; + class_valid = TRUE; + } + + smsc_addr = sms_decode_address (&pdu[1], 2 * (pdu[0] - 1)); + sender_addr = sms_decode_address (&pdu[msg_start_offset + 2], pdu[msg_start_offset + 1]); + sc_timestamp = sms_decode_timestamp (&pdu[tp_dcs_offset + 1]); + + properties = sms_properties_hash_new (smsc_addr, + sender_addr, + sc_timestamp, + msg_text, + pdu_data, + pdu[tp_dcs_offset] & 0xFF, + class_valid ? &msg_class : NULL); + g_assert (properties); + if (multipart) { + g_hash_table_insert (properties, "concat-reference", simple_uint_value (concat_ref)); + g_hash_table_insert (properties, "concat-max", simple_uint_value (concat_max)); + g_hash_table_insert (properties, "concat-sequence", simple_uint_value (concat_seq)); + } g_free (smsc_addr); g_free (sender_addr); g_free (sc_timestamp); g_free (msg_text); + g_byte_array_free (pdu_data, TRUE); g_free (pdu); - return properties; } + +static guint8 +validity_to_relative (guint validity) +{ + if (validity == 0) + return 167; /* 24 hours */ + + if (validity <= 720) { + /* 5 minute units up to 12 hours */ + if (validity % 5) + validity += 5; + return (validity / 5) - 1; + } + + if (validity > 720 && validity <= 1440) { + /* 12 hours + 30 minute units up to 1 day */ + if (validity % 30) + validity += 30; /* round up to next 30 minutes */ + validity = MIN (validity, 1440); + return 143 + ((validity - 720) / 30); + } + + if (validity > 1440 && validity <= 43200) { + /* 2 days up to 1 month */ + if (validity % 1440) + validity += 1440; /* round up to next day */ + validity = MIN (validity, 43200); + return 167 + ((validity - 1440) / 1440); + } + + /* 43200 = 30 days in minutes + * 10080 = 7 days in minutes + * 635040 = 63 weeks in minutes + * 40320 = 4 weeks in minutes + */ + if (validity > 43200 && validity <= 635040) { + /* 5 weeks up to 63 weeks */ + if (validity % 10080) + validity += 10080; /* round up to next week */ + validity = MIN (validity, 635040); + return 196 + ((validity - 40320) / 10080); + } + + return 255; /* 63 weeks */ +} + +#define PDU_SIZE 200 + +/** + * sms_create_submit_pdu: + * + * @number: the subscriber number to send this message to + * @text: the body of this SMS + * @smsc: if given, the SMSC address + * @validity: minutes until the SMS should expire in the SMSC, or 0 for a + * suitable default + * @class: unused + * @out_pdulen: on success, the size of the returned PDU in bytes + * @out_msgstart: on success, the byte index in the returned PDU where the + * message starts (ie, skipping the SMSC length byte and address, if present) + * @error: on error, filled with the error that occurred + * + * Constructs a single-part SMS message with the given details, preferring to + * use the UCS2 character set when the message will fit, otherwise falling back + * to the GSM character set. + * + * Returns: the constructed PDU data on success, or %NULL on error + **/ +guint8 * +sms_create_submit_pdu (const char *number, + const char *text, + const char *smsc, + guint validity, + guint class, + guint *out_pdulen, + guint *out_msgstart, + GError **error) +{ + guint8 *pdu; + guint len, offset = 0; + MMModemCharset best_cs = MM_MODEM_CHARSET_GSM; + guint ucs2len = 0, gsm_unsupported = 0; + guint textlen = 0; + + g_return_val_if_fail (number != NULL, NULL); + g_return_val_if_fail (text != NULL, NULL); + + /* FIXME: support multiple fragments */ + + textlen = mm_charset_get_encoded_len (text, MM_MODEM_CHARSET_GSM, &gsm_unsupported); + if (textlen > 160) { + g_set_error_literal (error, + MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, + "Cannot encode message to fit into an SMS."); + return NULL; + } + + /* If there are characters that are unsupported in the GSM charset, try + * UCS2. If the UCS2 encoded string is too long to fit in an SMS, then + * just use GSM and suck up the unconverted chars. + */ + if (gsm_unsupported > 0) { + ucs2len = mm_charset_get_encoded_len (text, MM_MODEM_CHARSET_UCS2, NULL); + if (ucs2len <= 140) { + best_cs = MM_MODEM_CHARSET_UCS2; + textlen = ucs2len; + } + } + + /* Build up the PDU */ + pdu = g_malloc0 (PDU_SIZE); + g_return_val_if_fail (pdu != NULL, NULL); + + if (smsc) { + len = sms_encode_address (smsc, pdu, PDU_SIZE, TRUE); + if (len == 0) { + g_set_error (error, + MM_MSG_ERROR, + MM_MSG_ERROR_INVALID_PDU_PARAMETER, + "Invalid SMSC address '%s'", smsc); + goto error; + } + offset += len; + } else { + /* No SMSC, use default */ + pdu[offset++] = 0x00; + } + + if (out_msgstart) + *out_msgstart = offset; + + if (validity > 0) + pdu[offset] = 1 << 4; /* TP-VP present; format RELATIVE */ + else + pdu[offset] = 0; /* TP-VP not present */ + pdu[offset++] |= 0x01; /* TP-MTI = SMS-SUBMIT */ + + pdu[offset++] = 0x00; /* TP-Message-Reference: filled by device */ + + len = sms_encode_address (number, &pdu[offset], PDU_SIZE - offset, FALSE); + if (len == 0) { + g_set_error (error, + MM_MSG_ERROR, + MM_MSG_ERROR_INVALID_PDU_PARAMETER, + "Invalid send-to number '%s'", number); + goto error; + } + offset += len; + + /* TP-PID */ + pdu[offset++] = 0x00; + + /* TP-DCS */ + if (best_cs == MM_MODEM_CHARSET_UCS2) + pdu[offset++] = 0x08; + else + pdu[offset++] = 0x00; /* GSM */ + + /* TP-Validity-Period: 4 days */ + if (validity > 0) + pdu[offset++] = validity_to_relative (validity); + + /* TP-User-Data-Length */ + pdu[offset++] = textlen; + + if (best_cs == MM_MODEM_CHARSET_GSM) { + guint8 *unpacked, *packed; + guint32 unlen = 0, packlen = 0; + + unpacked = mm_charset_utf8_to_unpacked_gsm (text, &unlen); + if (!unpacked || unlen == 0) { + g_free (unpacked); + g_set_error_literal (error, + MM_MSG_ERROR, + MM_MSG_ERROR_INVALID_PDU_PARAMETER, + "Failed to convert message text to GSM."); + goto error; + } + + packed = gsm_pack (unpacked, unlen, 0, &packlen); + g_free (unpacked); + if (!packed || packlen == 0) { + g_free (packed); + g_set_error_literal (error, + MM_MSG_ERROR, + MM_MSG_ERROR_INVALID_PDU_PARAMETER, + "Failed to pack message text to GSM."); + goto error; + } + + memcpy (&pdu[offset], packed, packlen); + g_free (packed); + offset += packlen; + } else if (best_cs == MM_MODEM_CHARSET_UCS2) { + GByteArray *array; + + array = g_byte_array_sized_new (textlen / 2); + if (!mm_modem_charset_byte_array_append (array, text, FALSE, best_cs)) { + g_byte_array_free (array, TRUE); + g_set_error_literal (error, + MM_MSG_ERROR, + MM_MSG_ERROR_INVALID_PDU_PARAMETER, + "Failed to convert message text to UCS2."); + goto error; + } + + memcpy (&pdu[offset], array->data, array->len); + offset += array->len; + g_byte_array_free (array, TRUE); + } else + g_assert_not_reached (); + + if (out_pdulen) + *out_pdulen = offset; + return pdu; + +error: + g_free (pdu); + return NULL; +} + diff --git a/src/mm-sms-utils.h b/src/mm-sms-utils.h index 26d9829..46f475b 100644 --- a/src/mm-sms-utils.h +++ b/src/mm-sms-utils.h @@ -22,4 +22,28 @@ GHashTable *sms_parse_pdu (const char *hexpdu, GError **error); +guint8 *sms_create_submit_pdu (const char *number, + const char *text, + const char *smsc, + guint validity, + guint class, + guint *out_pdulen, + guint *out_msgstart, + GError **error); + +GHashTable *sms_properties_hash_new (const char *smsc, + const char *number, + const char *timestamp, + const char *text, + const GByteArray *data, + guint data_coding_scheme, + guint *class); + +/* For testcases only */ +guint sms_encode_address (const char *address, + guint8 *buf, + size_t buflen, + gboolean is_smsc); + + #endif /* MM_SMS_UTILS_H */ diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index cc47e66..43b3eb1 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -5,6 +5,7 @@ noinst_PROGRAMS = \ test-modem-helpers \ test-charsets \ test-qcdm-serial-port \ + test-at-serial-port \ test-sms test_modem_helpers_SOURCES = \ @@ -41,6 +42,20 @@ test_qcdm_serial_port_LDADD = \ $(top_builddir)/libqcdm/src/libqcdm.la \ -lutil +test_at_serial_port_SOURCES = \ + test-at-serial-port.c + +test_at_serial_port_CPPFLAGS = \ + $(MM_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src + +test_at_serial_port_LDADD = \ + $(MM_LIBS) \ + $(top_builddir)/src/libserial.la \ + $(top_builddir)/src/libmodem-helpers.la \ + -lutil + test_sms_SOURCES = \ test-sms.c @@ -60,4 +75,3 @@ check-local: test-modem-helpers $(abs_builddir)/test-sms endif - diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in index 94793ef..d6c4d1a 100644 --- a/src/tests/Makefile.in +++ b/src/tests/Makefile.in @@ -35,7 +35,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = test-modem-helpers$(EXEEXT) test-charsets$(EXEEXT) \ - test-qcdm-serial-port$(EXEEXT) test-sms$(EXEEXT) + test-qcdm-serial-port$(EXEEXT) test-at-serial-port$(EXEEXT) \ + test-sms$(EXEEXT) subdir = src/tests DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -43,7 +44,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -51,14 +52,20 @@ CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) -am_test_charsets_OBJECTS = test_charsets-test-charsets.$(OBJEXT) -test_charsets_OBJECTS = $(am_test_charsets_OBJECTS) +am_test_at_serial_port_OBJECTS = \ + test_at_serial_port-test-at-serial-port.$(OBJEXT) +test_at_serial_port_OBJECTS = $(am_test_at_serial_port_OBJECTS) am__DEPENDENCIES_1 = -test_charsets_DEPENDENCIES = $(top_builddir)/src/libmodem-helpers.la \ - $(am__DEPENDENCIES_1) +test_at_serial_port_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(top_builddir)/src/libserial.la \ + $(top_builddir)/src/libmodem-helpers.la AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent +am_test_charsets_OBJECTS = test_charsets-test-charsets.$(OBJEXT) +test_charsets_OBJECTS = $(am_test_charsets_OBJECTS) +test_charsets_DEPENDENCIES = $(top_builddir)/src/libmodem-helpers.la \ + $(am__DEPENDENCIES_1) am_test_modem_helpers_OBJECTS = \ test_modem_helpers-test-modem-helpers.$(OBJEXT) test_modem_helpers_OBJECTS = $(am_test_modem_helpers_OBJECTS) @@ -104,10 +111,12 @@ am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; -SOURCES = $(test_charsets_SOURCES) $(test_modem_helpers_SOURCES) \ - $(test_qcdm_serial_port_SOURCES) $(test_sms_SOURCES) -DIST_SOURCES = $(test_charsets_SOURCES) $(test_modem_helpers_SOURCES) \ - $(test_qcdm_serial_port_SOURCES) $(test_sms_SOURCES) +SOURCES = $(test_at_serial_port_SOURCES) $(test_charsets_SOURCES) \ + $(test_modem_helpers_SOURCES) $(test_qcdm_serial_port_SOURCES) \ + $(test_sms_SOURCES) +DIST_SOURCES = $(test_at_serial_port_SOURCES) $(test_charsets_SOURCES) \ + $(test_modem_helpers_SOURCES) $(test_qcdm_serial_port_SOURCES) \ + $(test_sms_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -299,6 +308,20 @@ test_qcdm_serial_port_LDADD = \ $(top_builddir)/libqcdm/src/libqcdm.la \ -lutil +test_at_serial_port_SOURCES = \ + test-at-serial-port.c + +test_at_serial_port_CPPFLAGS = \ + $(MM_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src + +test_at_serial_port_LDADD = \ + $(MM_LIBS) \ + $(top_builddir)/src/libserial.la \ + $(top_builddir)/src/libmodem-helpers.la \ + -lutil + test_sms_SOURCES = \ test-sms.c @@ -352,6 +375,9 @@ clean-noinstPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list +test-at-serial-port$(EXEEXT): $(test_at_serial_port_OBJECTS) $(test_at_serial_port_DEPENDENCIES) + @rm -f test-at-serial-port$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_at_serial_port_OBJECTS) $(test_at_serial_port_LDADD) $(LIBS) test-charsets$(EXEEXT): $(test_charsets_OBJECTS) $(test_charsets_DEPENDENCIES) @rm -f test-charsets$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_charsets_OBJECTS) $(test_charsets_LDADD) $(LIBS) @@ -371,6 +397,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_at_serial_port-test-at-serial-port.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_charsets-test-charsets.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_modem_helpers-test-modem-helpers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_qcdm_serial_port-test-qcdm-serial-port.Po@am__quote@ @@ -403,6 +430,22 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< +test_at_serial_port-test-at-serial-port.o: test-at-serial-port.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_at_serial_port_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_at_serial_port-test-at-serial-port.o -MD -MP -MF $(DEPDIR)/test_at_serial_port-test-at-serial-port.Tpo -c -o test_at_serial_port-test-at-serial-port.o `test -f 'test-at-serial-port.c' || echo '$(srcdir)/'`test-at-serial-port.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_at_serial_port-test-at-serial-port.Tpo $(DEPDIR)/test_at_serial_port-test-at-serial-port.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-at-serial-port.c' object='test_at_serial_port-test-at-serial-port.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_at_serial_port_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_at_serial_port-test-at-serial-port.o `test -f 'test-at-serial-port.c' || echo '$(srcdir)/'`test-at-serial-port.c + +test_at_serial_port-test-at-serial-port.obj: test-at-serial-port.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_at_serial_port_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_at_serial_port-test-at-serial-port.obj -MD -MP -MF $(DEPDIR)/test_at_serial_port-test-at-serial-port.Tpo -c -o test_at_serial_port-test-at-serial-port.obj `if test -f 'test-at-serial-port.c'; then $(CYGPATH_W) 'test-at-serial-port.c'; else $(CYGPATH_W) '$(srcdir)/test-at-serial-port.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_at_serial_port-test-at-serial-port.Tpo $(DEPDIR)/test_at_serial_port-test-at-serial-port.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-at-serial-port.c' object='test_at_serial_port-test-at-serial-port.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_at_serial_port_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_at_serial_port-test-at-serial-port.obj `if test -f 'test-at-serial-port.c'; then $(CYGPATH_W) 'test-at-serial-port.c'; else $(CYGPATH_W) '$(srcdir)/test-at-serial-port.c'; fi` + test_charsets-test-charsets.o: test-charsets.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_charsets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_charsets-test-charsets.o -MD -MP -MF $(DEPDIR)/test_charsets-test-charsets.Tpo -c -o test_charsets-test-charsets.o `test -f 'test-charsets.c' || echo '$(srcdir)/'`test-charsets.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_charsets-test-charsets.Tpo $(DEPDIR)/test_charsets-test-charsets.Po diff --git a/src/tests/test-at-serial-port.c b/src/tests/test-at-serial-port.c new file mode 100644 index 0000000..c46fa88 --- /dev/null +++ b/src/tests/test-at-serial-port.c @@ -0,0 +1,86 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details: + * + * Copyright (C) 2012 Aleksander Morgado + */ + +#include +#include +#include + +#include "mm-errors.h" +#include "mm-at-serial-port.h" +#include "mm-log.h" + +typedef struct { + gchar *original; + gchar *without_echo; +} EchoRemovalTest; + +static const EchoRemovalTest echo_removal_tests[] = { + { "\r\n", "\r\n" }, + { "\r", "\r" }, + { "\n", "\n" }, + { "this is a string that ends just with \r", "this is a string that ends just with \r" }, + { "this is a string that ends just with \n", "this is a string that ends just with \n" }, + { "\r\nthis is valid", "\r\nthis is valid" }, + { "a\r\nthis is valid", "\r\nthis is valid" }, + { "a\r\n", "\r\n" }, + { "all this string is to be considered echo\r\n", "\r\n" }, + { "all this string is to be considered echo\r\nthis is valid", "\r\nthis is valid" }, + { "echo echo\r\nthis is valid\r\nand so is this", "\r\nthis is valid\r\nand so is this" }, + { "\r\nthis is valid\r\nand so is this", "\r\nthis is valid\r\nand so is this" }, + { "\r\nthis is valid\r\nand so is this\r\n", "\r\nthis is valid\r\nand so is this\r\n" }, +}; + +static void +at_serial_echo_removal (void) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (echo_removal_tests); i++) { + GByteArray *ba; + + /* Note that we add last NUL also to the byte array, so that we can compare + * C strings later on */ + ba = g_byte_array_sized_new (strlen (echo_removal_tests[i].original) + 1); + g_byte_array_prepend (ba, + (guint8 *)echo_removal_tests[i].original, + strlen (echo_removal_tests[i].original) + 1); + + mm_at_serial_port_remove_echo (ba); + + g_assert_cmpstr ((gchar *)ba->data, ==, echo_removal_tests[i].without_echo); + + g_byte_array_unref (ba); + } +} + +void +_mm_log (const char *loc, + const char *func, + guint32 level, + const char *fmt, + ...) +{ + /* Dummy log function */ +} + +int main (int argc, char **argv) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/ModemManager/AT-serial/echo-removal", at_serial_echo_removal); + + return g_test_run (); +} diff --git a/src/tests/test-charsets.c b/src/tests/test-charsets.c index 70c796a..f954d93 100644 --- a/src/tests/test-charsets.c +++ b/src/tests/test-charsets.c @@ -284,6 +284,48 @@ test_pack_gsm7_24_chars (void *f, gpointer d) g_free (packed); } +static void +test_pack_gsm7_last_septet_alone (void *f, gpointer d) +{ + static const guint8 unpacked[] = { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x61, 0x6C, + 0x6C, 0x79, 0x20, 0x63, 0x6F, 0x6F, 0x6C, 0x20, 0x10, 0x10, 0x10, 0x10, + 0x10 + }; + static const guint8 expected[] = { + 0x54, 0x74, 0x7A, 0x0E, 0x4A, 0xCF, 0x41, 0xF2, 0x72, 0x98, 0xCD, 0xCE, + 0x83, 0xC6, 0xEF, 0x37, 0x1B, 0x04, 0x81, 0x40, 0x20, 0x10 + }; + guint8 *packed; + guint32 packed_len = 0; + + /* Tests that a 25-character unpacked string (where, when packed, the last + * septet will be in an octet by itself) packs correctly. + */ + + packed = gsm_pack (unpacked, sizeof (unpacked), 0, &packed_len); + g_assert (packed); + g_assert_cmpint (packed_len, ==, sizeof (expected)); + + g_free (packed); +} + +static void +test_pack_gsm7_7_chars_offset (void *f, gpointer d) +{ + static const guint8 unpacked[] = { 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x10, 0x2F }; + static const guint8 expected[] = { 0x00, 0x5D, 0x66, 0xB3, 0xDF, 0x90, 0x17 }; + guint8 *packed; + guint32 packed_len = 0; + + packed = gsm_pack (unpacked, sizeof (unpacked), 5, &packed_len); + g_assert (packed); + g_assert_cmpint (packed_len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (packed, expected, packed_len), ==, 0); + + g_free (packed); +} + #if GLIB_CHECK_VERSION(2,25,12) typedef GTestFixtureFunc TCFunc; @@ -314,6 +356,9 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_pack_gsm7_7_chars, NULL)); g_test_suite_add (suite, TESTCASE (test_pack_gsm7_all_chars, NULL)); g_test_suite_add (suite, TESTCASE (test_pack_gsm7_24_chars, NULL)); + g_test_suite_add (suite, TESTCASE (test_pack_gsm7_last_septet_alone, NULL)); + + g_test_suite_add (suite, TESTCASE (test_pack_gsm7_7_chars_offset, NULL)); result = g_test_run (); diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c index d07f0d4..3b8e2e2 100644 --- a/src/tests/test-modem-helpers.c +++ b/src/tests/test-modem-helpers.c @@ -491,8 +491,9 @@ test_creg_match (const char *test, g_assert (data); g_assert (result); - g_print ("\nTesting %s +CREG %s response...\n", + g_print ("\nTesting %s +C%sREG %s response...\n", test, + result->cgreg ? "G" : "", solicited ? "solicited" : "unsolicited"); array = solicited ? data->solicited_creg : data->unsolicited_creg; @@ -742,6 +743,16 @@ test_creg2_gobi_weird_solicited (void *f, gpointer d) test_creg_match ("Qualcomm Gobi 1000 CREG=2", TRUE, reply, data, &result); } +static void +test_cgreg2_unsolicited_with_rac (void *f, gpointer d) +{ + TestData *data = (TestData *) d; + const char *reply = "\r\n+CGREG: 1,\"1422\",\"00000142\",3,\"00\"\r\n"; + const CregResult result = { 1, 0x1422, 0x0142, 3, 8, TRUE }; + + test_creg_match ("CGREG=2 with RAC", FALSE, reply, data, &result); +} + static void test_cscs_icon225_support_response (void *f, gpointer d) { @@ -1269,6 +1280,7 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_cgreg2_f3607gw_unsolicited, data)); g_test_suite_add (suite, TESTCASE (test_cgreg2_md400_unsolicited, data)); g_test_suite_add (suite, TESTCASE (test_cgreg2_x220_unsolicited, data)); + g_test_suite_add (suite, TESTCASE (test_cgreg2_unsolicited_with_rac, data)); g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi_unsolicited, data)); g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi2_unsolicited, data)); diff --git a/src/tests/test-qcdm-serial-port.c b/src/tests/test-qcdm-serial-port.c index 3aeed6a..c31011b 100644 --- a/src/tests/test-qcdm-serial-port.c +++ b/src/tests/test-qcdm-serial-port.c @@ -31,6 +31,7 @@ #include "libqcdm/src/commands.h" #include "libqcdm/src/utils.h" #include "libqcdm/src/com.h" +#include "libqcdm/src/errors.h" #include "mm-log.h" typedef struct { @@ -135,8 +136,9 @@ server_wait_request (int fd, char *buf, gsize len) retries++; continue; } else if (bytes_read == 1) { - gboolean more = FALSE, success; + gboolean success; gsize used = 0; + qcdmbool more = FALSE; total++; decap_len = 0; @@ -187,17 +189,14 @@ qcdm_verinfo_expect_success_cb (MMQcdmSerialPort *port, static void qcdm_request_verinfo (MMQcdmSerialPort *port, VerInfoCb cb, GMainLoop *loop) { - GError *error = NULL; GByteArray *verinfo; gint len; /* Build up the probe command */ verinfo = g_byte_array_sized_new (50); - len = qcdm_cmd_version_info_new ((char *) verinfo->data, 50, &error); - if (len <= 0) { + len = qcdm_cmd_version_info_new ((char *) verinfo->data, 50); + if (len <= 0) g_byte_array_free (verinfo, TRUE); - g_assert_no_error (error); - } verinfo->len = len; mm_qcdm_serial_port_queue_command (port, verinfo, 3, cb, loop); @@ -400,9 +399,7 @@ test_pty_create (gpointer user_data) { TestData *d = user_data; struct termios stbuf; - int ret; - GError *error = NULL; - gboolean success; + int ret, err; ret = openpty (&d->master, &d->slave, NULL, NULL, NULL); g_assert (ret == 0); @@ -417,9 +414,8 @@ test_pty_create (gpointer user_data) fcntl (d->slave, F_SETFL, O_NONBLOCK); fcntl (d->master, F_SETFL, O_NONBLOCK); - success = qcdm_port_setup (d->master, &error); - g_assert_no_error (error); - g_assert (success); + err = qcdm_port_setup (d->master); + g_assert_cmpint (err, ==, QCDM_SUCCESS); } static void diff --git a/src/tests/test-sms.c b/src/tests/test-sms.c index bd18c0b..5c32ad1 100644 --- a/src/tests/test-sms.c +++ b/src/tests/test-sms.c @@ -20,6 +20,7 @@ #include "mm-sms-utils.h" #include "mm-utils.h" +#include "dbus/dbus-glib.h" #define TEST_ENTRY_EQ(hash, key, expectvalue) do { \ @@ -30,6 +31,27 @@ g_assert_cmpstr(g_value_get_string(value), ==, (expectvalue)); \ } while (0) +#define TEST_UINT_ENTRY_EQ(hash, key, expectvalue) do { \ + GValue *value; \ + value = g_hash_table_lookup((hash), (key)); \ + g_assert(value); \ + g_assert(G_VALUE_HOLDS_UINT(value)); \ + g_assert_cmpint(g_value_get_uint(value), ==, (expectvalue)); \ + } while (0) + +#define TEST_ARRAY_ENTRY_EQ(hash, key, expectvalue) do { \ + GValue *value; \ + GByteArray *tmp; \ + guint32 i; \ + value = g_hash_table_lookup((hash), (key)); \ + g_assert(value); \ + g_assert(G_VALUE_HOLDS(value, DBUS_TYPE_G_UCHAR_ARRAY)); \ + tmp = g_value_get_boxed (value); \ + g_assert_cmpint (tmp->len, ==, sizeof (expectvalue)); \ + for (i = 0; i < tmp->len; i++) \ + g_assert_cmpint (tmp->data[i], ==, expectvalue[i]); \ + } while (0) + static void test_pdu1 (void *f, gpointer d) { @@ -52,7 +74,7 @@ test_pdu1 (void *f, gpointer d) 0x28, 0xec, 0x26, 0x83, 0xbe, 0x60, 0x50, 0x78, 0x0e, 0xba, 0x97, 0xd9, 0x6c, 0x17}; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -80,7 +102,7 @@ test_pdu2 (void *f, gpointer d) 0x30, 0x92, 0x91, 0x02, 0x40, 0x61, 0x08, 0x04, 0x42, 0x04, 0x35, 0x04, 0x41, 0x04, 0x42}; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -106,7 +128,7 @@ test_pdu3 (void *f, gpointer d) 0x65, 0x00, 0x0a, 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37}; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -134,7 +156,7 @@ test_pdu3_nzpid (void *f, gpointer d) 0x65, 0x00, 0x0a, 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37}; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -163,7 +185,7 @@ test_pdu3_mms (void *f, gpointer d) 0x65, 0x00, 0x0a, 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37}; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -191,7 +213,7 @@ test_pdu3_natl (void *f, gpointer d) 0x65, 0x00, 0x0a, 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37}; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -217,8 +239,10 @@ test_pdu3_8bit (void *f, gpointer d) 0xf2, 0x00, 0x04, 0x11, 0x10, 0x10, 0x21, 0x43, 0x65, 0x00, 0x0a, 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37, 0xde}; + static const guint8 expected_data[] = { + 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37, 0xde }; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -228,7 +252,9 @@ test_pdu3_8bit (void *f, gpointer d) TEST_ENTRY_EQ (sms, "smsc", "+12345678901"); TEST_ENTRY_EQ (sms, "number", "+18005551212"); TEST_ENTRY_EQ (sms, "timestamp", "110101123456+00"); - TEST_ENTRY_EQ (sms, "text", "\xe8\x32\x9b\xfd\x46\x97\xd9\xec\x37\xde"); + TEST_ENTRY_EQ (sms, "text", ""); + TEST_UINT_ENTRY_EQ (sms, "data-coding-scheme", 0x04); + TEST_ARRAY_ENTRY_EQ (sms, "data", expected_data); g_free (hexpdu); g_hash_table_unref (sms); @@ -272,7 +298,7 @@ test_pdu_dcsf1 (void *f, gpointer d) 0x00, 0x47, 0xBF, 0xDD, 0x65, 0x50, 0xB8, 0x0E, 0xCA, 0xD9, 0x66}; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -301,8 +327,10 @@ test_pdu_dcsf_8bit (void *f, gpointer d) 0xf2, 0x00, 0xf4, 0x11, 0x10, 0x10, 0x21, 0x43, 0x65, 0x00, 0x0a, 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37, 0xde}; + static const guint8 expected_data[] = { + 0xe8, 0x32, 0x9b, 0xfd, 0x46, 0x97, 0xd9, 0xec, 0x37, 0xde }; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -312,7 +340,9 @@ test_pdu_dcsf_8bit (void *f, gpointer d) TEST_ENTRY_EQ (sms, "smsc", "+12345678901"); TEST_ENTRY_EQ (sms, "number", "+18005551212"); TEST_ENTRY_EQ (sms, "timestamp", "110101123456+00"); - TEST_ENTRY_EQ (sms, "text", "\xe8\x32\x9b\xfd\x46\x97\xd9\xec\x37\xde"); + TEST_ENTRY_EQ (sms, "text", ""); + TEST_UINT_ENTRY_EQ (sms, "data-coding-scheme", 0xF4); + TEST_ARRAY_ENTRY_EQ (sms, "data", expected_data); g_free (hexpdu); g_hash_table_unref (sms); @@ -329,7 +359,7 @@ test_pdu_insufficient_data (void *f, gpointer d) 0x97, 0xd9, 0xec, 0x37 }; GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu, sizeof(pdu)); @@ -351,7 +381,7 @@ test_pdu_udhi (void *f, gpointer d) "5C7683D27350984D4FABC9A0B33C4C4FCF5D20EBFB2D079DCB62793DBD06D9C36E50FB2D4E97D9" "A0B49B5E96BBCB"; GHashTable *sms; - GError *error; + GError *error = NULL; sms = sms_parse_pdu (hexpdu, &error); g_assert (sms); @@ -372,7 +402,7 @@ static void test_pduX (void *f, gpointer d) { GHashTable *sms; - GError *error; + GError *error = NULL; char *hexpdu; hexpdu = utils_bin2hexstr (pdu1, sizeof(pdu1)); @@ -390,7 +420,225 @@ test_pduX (void *f, gpointer d) } #endif +static void +test_encode_sms_addr_encode_smsc_intl (void *f, gpointer d) +{ + static const char *addr = "+19037029920"; + static const guint8 expected[] = { 0x07, 0x91, 0x91, 0x30, 0x07, 0x92, 0x29, 0xF0 }; + guint enclen; + guint8 buf[20]; + + enclen = sms_encode_address (addr, buf, sizeof (buf), TRUE); + g_assert_cmpint (enclen, ==, sizeof (expected)); + g_assert_cmpint (memcmp (buf, expected, sizeof (expected)), ==, 0); +} + +static void +test_encode_sms_addr_encode_smsc_unknown (void *f, gpointer d) +{ + static const char *addr = "9037029920"; + static const guint8 expected[] = { 0x06, 0x81, 0x09, 0x73, 0x20, 0x99, 0x02 }; + guint enclen; + guint8 buf[20]; + + enclen = sms_encode_address (addr, buf, sizeof (buf), TRUE); + g_assert_cmpint (enclen, ==, sizeof (expected)); + g_assert_cmpint (memcmp (buf, expected, sizeof (expected)), ==, 0); +} + +static void +test_encode_sms_addr_encode_intl (void *f, gpointer d) +{ + static const char *addr = "+19037029920"; + static const guint8 expected[] = { 0x0B, 0x91, 0x91, 0x30, 0x07, 0x92, 0x29, 0xF0 }; + guint enclen; + guint8 buf[20]; + + enclen = sms_encode_address (addr, buf, sizeof (buf), FALSE); + g_assert_cmpint (enclen, ==, sizeof (expected)); + g_assert_cmpint (memcmp (buf, expected, sizeof (expected)), ==, 0); +} + +static void +test_encode_sms_addr_encode_unknown (void *f, gpointer d) +{ + static const char *addr = "9037029920"; + static const guint8 expected[] = { 0x0A, 0x81, 0x09, 0x73, 0x20, 0x99, 0x02 }; + guint enclen; + guint8 buf[20]; + + enclen = sms_encode_address (addr, buf, sizeof (buf), FALSE); + g_assert_cmpint (enclen, ==, sizeof (expected)); + g_assert_cmpint (memcmp (buf, expected, sizeof (expected)), ==, 0); +} + +static void +test_create_pdu_ucs2_with_smsc (void *f, gpointer d) +{ + static const char *smsc = "+19037029920"; + static const char *number = "+15555551234"; + static const char *text = "Да здравствует король, детка!"; + static const guint8 expected[] = { + 0x07, 0x91, 0x91, 0x30, 0x07, 0x92, 0x29, 0xF0, 0x11, 0x00, 0x0B, 0x91, + 0x51, 0x55, 0x55, 0x15, 0x32, 0xF4, 0x00, 0x08, 0x00, 0x3A, 0x04, 0x14, + 0x04, 0x30, 0x00, 0x20, 0x04, 0x37, 0x04, 0x34, 0x04, 0x40, 0x04, 0x30, + 0x04, 0x32, 0x04, 0x41, 0x04, 0x42, 0x04, 0x32, 0x04, 0x43, 0x04, 0x35, + 0x04, 0x42, 0x00, 0x20, 0x04, 0x3A, 0x04, 0x3E, 0x04, 0x40, 0x04, 0x3E, + 0x04, 0x3B, 0x04, 0x4C, 0x00, 0x2C, 0x00, 0x20, 0x04, 0x34, 0x04, 0x35, + 0x04, 0x42, 0x04, 0x3A, 0x04, 0x30, 0x00, 0x21 + }; + guint8 *pdu; + guint len = 0, msgstart = 0; + GError *error = NULL; + + pdu = sms_create_submit_pdu (number, text, smsc, 5, 0, &len, &msgstart, &error); + g_assert_no_error (error); + g_assert (pdu); + g_assert_cmpint (len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (pdu, expected, len), ==, 0); + g_assert_cmpint (msgstart, ==, 8); +} + +static void +test_create_pdu_ucs2_no_smsc (void *f, gpointer d) +{ + static const char *number = "+15555551234"; + static const char *text = "Да здравствует король, детка!"; + static const guint8 expected[] = { + 0x00, 0x11, 0x00, 0x0B, 0x91, 0x51, 0x55, 0x55, 0x15, 0x32, 0xF4, 0x00, + 0x08, 0x00, 0x3A, 0x04, 0x14, 0x04, 0x30, 0x00, 0x20, 0x04, 0x37, 0x04, + 0x34, 0x04, 0x40, 0x04, 0x30, 0x04, 0x32, 0x04, 0x41, 0x04, 0x42, 0x04, + 0x32, 0x04, 0x43, 0x04, 0x35, 0x04, 0x42, 0x00, 0x20, 0x04, 0x3A, 0x04, + 0x3E, 0x04, 0x40, 0x04, 0x3E, 0x04, 0x3B, 0x04, 0x4C, 0x00, 0x2C, 0x00, + 0x20, 0x04, 0x34, 0x04, 0x35, 0x04, 0x42, 0x04, 0x3A, 0x04, 0x30, 0x00, + 0x21 + }; + guint8 *pdu; + guint len = 0, msgstart = 0; + GError *error = NULL; + + pdu = sms_create_submit_pdu (number, text, NULL, 5, 0, &len, &msgstart, &error); + g_assert_no_error (error); + g_assert (pdu); + g_assert_cmpint (len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (pdu, expected, len), ==, 0); + g_assert_cmpint (msgstart, ==, 1); +} + +static void +test_create_pdu_gsm_with_smsc (void *f, gpointer d) +{ + static const char *smsc = "+19037029920"; + static const char *number = "+15555551234"; + static const char *text = "Hi there...Tue 17th Jan 2012 05:30.18 pm (GMT+1) ΔΔΔΔΔ"; + static const guint8 expected[] = { + 0x07, 0x91, 0x91, 0x30, 0x07, 0x92, 0x29, 0xF0, 0x11, 0x00, 0x0B, 0x91, + 0x51, 0x55, 0x55, 0x15, 0x32, 0xF4, 0x00, 0x00, 0x00, 0x36, 0xC8, 0x34, + 0x88, 0x8E, 0x2E, 0xCB, 0xCB, 0x2E, 0x97, 0x8B, 0x5A, 0x2F, 0x83, 0x62, + 0x37, 0x3A, 0x1A, 0xA4, 0x0C, 0xBB, 0x41, 0x32, 0x58, 0x4C, 0x06, 0x82, + 0xD5, 0x74, 0x33, 0x98, 0x2B, 0x86, 0x03, 0xC1, 0xDB, 0x20, 0xD4, 0xB1, + 0x49, 0x5D, 0xC5, 0x52, 0x20, 0x08, 0x04, 0x02, 0x81, 0x00 + }; + guint8 *pdu; + guint len = 0, msgstart = 0; + GError *error = NULL; + + pdu = sms_create_submit_pdu (number, text, smsc, 5, 0, &len, &msgstart, &error); + g_assert_no_error (error); + g_assert (pdu); + g_assert_cmpint (len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (pdu, expected, len), ==, 0); + g_assert_cmpint (msgstart, ==, 8); +} + +static void +test_create_pdu_gsm_no_smsc (void *f, gpointer d) +{ + static const char *number = "+15555551234"; + static const char *text = "Hi there...Tue 17th Jan 2012 05:30.18 pm (GMT+1) ΔΔΔΔΔ"; + static const guint8 expected[] = { + 0x00, 0x11, 0x00, 0x0B, 0x91, 0x51, 0x55, 0x55, 0x15, 0x32, 0xF4, 0x00, + 0x00, 0x00, 0x36, 0xC8, 0x34, 0x88, 0x8E, 0x2E, 0xCB, 0xCB, 0x2E, 0x97, + 0x8B, 0x5A, 0x2F, 0x83, 0x62, 0x37, 0x3A, 0x1A, 0xA4, 0x0C, 0xBB, 0x41, + 0x32, 0x58, 0x4C, 0x06, 0x82, 0xD5, 0x74, 0x33, 0x98, 0x2B, 0x86, 0x03, + 0xC1, 0xDB, 0x20, 0xD4, 0xB1, 0x49, 0x5D, 0xC5, 0x52, 0x20, 0x08, 0x04, + 0x02, 0x81, 0x00 + }; + guint8 *pdu; + guint len = 0, msgstart = 0; + GError *error = NULL; + + pdu = sms_create_submit_pdu (number, text, NULL, 5, 0, &len, &msgstart, &error); + g_assert_no_error (error); + g_assert (pdu); + g_assert_cmpint (len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (pdu, expected, len), ==, 0); + g_assert_cmpint (msgstart, ==, 1); +} + +static void +test_create_pdu_gsm_3 (void *f, gpointer d) +{ + static const char *number = "+15556661234"; + static const char *text = "This is really cool ΔΔΔΔΔ"; + static const guint8 expected[] = { + 0x00, 0x11, 0x00, 0x0B, 0x91, 0x51, 0x55, 0x66, 0x16, 0x32, 0xF4, 0x00, + 0x00, 0x00, 0x19, 0x54, 0x74, 0x7A, 0x0E, 0x4A, 0xCF, 0x41, 0xF2, 0x72, + 0x98, 0xCD, 0xCE, 0x83, 0xC6, 0xEF, 0x37, 0x1B, 0x04, 0x81, 0x40, 0x20, + 0x10 + }; + guint8 *pdu; + guint len = 0, msgstart = 0; + GError *error = NULL; + + /* Tests that a 25-character message (where the last septet is packed into + * an octet by itself) is created correctly. Previous to + * "core: fix some bugs in GSM7 packing code" the GSM packing code would + * leave off the last octet. + */ + + pdu = sms_create_submit_pdu (number, text, NULL, 5, 0, &len, &msgstart, &error); + g_assert_no_error (error); + g_assert (pdu); + g_assert_cmpint (len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (pdu, expected, len), ==, 0); + g_assert_cmpint (msgstart, ==, 1); +} + +static void +test_create_pdu_gsm_no_validity (void *f, gpointer d) +{ + static const char *number = "+15556661234"; + static const char *text = "This is really cool ΔΔΔΔΔ"; + static const guint8 expected[] = { + 0x00, 0x01, 0x00, 0x0B, 0x91, 0x51, 0x55, 0x66, 0x16, 0x32, 0xF4, 0x00, + 0x00, 0x19, 0x54, 0x74, 0x7A, 0x0E, 0x4A, 0xCF, 0x41, 0xF2, 0x72, 0x98, + 0xCD, 0xCE, 0x83, 0xC6, 0xEF, 0x37, 0x1B, 0x04, 0x81, 0x40, 0x20, 0x10 + }; + guint8 *pdu; + guint len = 0, msgstart = 0; + GError *error = NULL; + + pdu = sms_create_submit_pdu (number, text, NULL, 0, 0, &len, &msgstart, &error); + g_assert_no_error (error); + g_assert (pdu); + g_assert_cmpint (len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (pdu, expected, len), ==, 0); + g_assert_cmpint (msgstart, ==, 1); +} +#if 0 +{ +int i; +g_print ("\n "); +for (i = 0; i < len; i++) { + g_print (" 0x%02X", pdu[i]); + if (((i + 1) % 12) == 0) + g_print ("\n "); +} +g_print ("\n"); +} +#endif #if GLIB_CHECK_VERSION(2,25,12) typedef GTestFixtureFunc TCFunc; @@ -423,6 +671,19 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_pdu_insufficient_data, NULL)); g_test_suite_add (suite, TESTCASE (test_pdu_udhi, NULL)); + g_test_suite_add (suite, TESTCASE (test_encode_sms_addr_encode_smsc_intl, NULL)); + g_test_suite_add (suite, TESTCASE (test_encode_sms_addr_encode_smsc_unknown, NULL)); + g_test_suite_add (suite, TESTCASE (test_encode_sms_addr_encode_intl, NULL)); + g_test_suite_add (suite, TESTCASE (test_encode_sms_addr_encode_unknown, NULL)); + + g_test_suite_add (suite, TESTCASE (test_create_pdu_ucs2_with_smsc, NULL)); + g_test_suite_add (suite, TESTCASE (test_create_pdu_ucs2_no_smsc, NULL)); + g_test_suite_add (suite, TESTCASE (test_create_pdu_gsm_with_smsc, NULL)); + g_test_suite_add (suite, TESTCASE (test_create_pdu_gsm_no_smsc, NULL)); + + g_test_suite_add (suite, TESTCASE (test_create_pdu_gsm_3, NULL)); + g_test_suite_add (suite, TESTCASE (test_create_pdu_gsm_no_validity, NULL)); + result = g_test_run (); return result; diff --git a/test/Makefile.am b/test/Makefile.am index 8249131..ccec30a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -25,6 +25,9 @@ EXTRA_DIST = \ info.py \ list-modems.py \ location.py \ - mm-send-sms.py \ - send-pin.py + sms-send.py \ + sms-get.py \ + send-pin.py \ + ussd.py \ + scan.py diff --git a/test/Makefile.in b/test/Makefile.in index c27c0ce..3df9166 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -43,7 +43,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -293,8 +293,11 @@ EXTRA_DIST = \ info.py \ list-modems.py \ location.py \ - mm-send-sms.py \ - send-pin.py + sms-send.py \ + sms-get.py \ + send-pin.py \ + ussd.py \ + scan.py all: all-am diff --git a/test/disable.py b/test/disable.py index 5b8c14a..4e52cf1 100755 --- a/test/disable.py +++ b/test/disable.py @@ -21,7 +21,10 @@ MM_DBUS_PATH='/org/freedesktop/ModemManager' MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem' bus = dbus.SystemBus() -proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1]) +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/" + str(objpath) +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM) modem.Enable (False) diff --git a/test/enable.py b/test/enable.py index bfe1a6d..7fa218d 100755 --- a/test/enable.py +++ b/test/enable.py @@ -21,7 +21,10 @@ MM_DBUS_PATH='/org/freedesktop/ModemManager' MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem' bus = dbus.SystemBus() -proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1]) +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/" + str(objpath) +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM) modem.Enable (True) diff --git a/test/info.py b/test/info.py index 6659a3a..82057fa 100755 --- a/test/info.py +++ b/test/info.py @@ -224,8 +224,10 @@ def gsm_inspect(proxy, props): bus = dbus.SystemBus() -bus = dbus.SystemBus() -proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1]) +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/%s" % str(objpath) +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) # Properties props = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Properties') diff --git a/test/location.py b/test/location.py index b6af387..96cd1e5 100755 --- a/test/location.py +++ b/test/location.py @@ -29,7 +29,10 @@ MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI = 0x00000002 MM_MODEM_LOCATION_CAPABILITY_GPS_RAW = 0x00000004 bus = dbus.SystemBus() -proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1]) +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/" + str(objpath) +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM) props = dbus.Interface(proxy, dbus_interface=DBUS_INTERFACE_PROPERTIES) diff --git a/test/mm-send-sms.py b/test/mm-send-sms.py deleted file mode 100755 index 55d453c..0000000 --- a/test/mm-send-sms.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/python -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 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 General Public License for more details: -# -# Copyright (C) 2009 Novell, Inc. -# - -# An example on how to send an SMS message using ModemManager - -import sys -import dbus - -if len(sys.argv) != 3: - print "Usage: %s " % sys.argv[0] - sys.exit(1) - -number = sys.argv[1] -message = sys.argv[2] - -bus = dbus.SystemBus() - -manager_proxy = bus.get_object('org.freedesktop.ModemManager', '/org/freedesktop/ModemManager') -manager_iface = dbus.Interface(manager_proxy, dbus_interface='org.freedesktop.ModemManager') -modems = manager_iface.EnumerateDevices() -if len(modems) == 0: - print "No modems found" - sys.exit(1) - -proxy = bus.get_object('org.freedesktop.ModemManager', modems[0]) -modem = dbus.Interface(proxy, dbus_interface='org.freedesktop.ModemManager.Modem') -modem.Enable(True) - -msg_dict = dbus.Dictionary({ dbus.String('number') : dbus.String(number), - dbus.String('text') : dbus.String(message) - }, - signature=dbus.Signature("sv")) - -sms_iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.ModemManager.Modem.Gsm.SMS') -try: - sms_iface.Send(msg_dict) -except: - print "Sending message failed" -finally: - modem.Enable(False) diff --git a/test/scan.py b/test/scan.py new file mode 100755 index 0000000..eff470d --- /dev/null +++ b/test/scan.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details: +# +# Copyright (C) 2009 - 2010Red Hat, Inc. +# + +import sys, dbus + +DBUS_INTERFACE_PROPERTIES='org.freedesktop.DBus.Properties' +MM_DBUS_SERVICE='org.freedesktop.ModemManager' +MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem' +MM_DBUS_INTERFACE_MODEM_GSM_NETWORK='org.freedesktop.ModemManager.Modem.Gsm.Network' + +gsm_act = { 0: "(GSM)", + 1: "(GSM Compact)", + 2: "(UMTS)", + 3: "(EDGE)", + 4: "(HSDPA)", + 5: "(HSUPA)", + 6: "(HSPA)" + } + +bus = dbus.SystemBus() +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/" + str(objpath) +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) + +# Properties +props = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Properties') + +mtype = props.Get(MM_DBUS_INTERFACE_MODEM, 'Type') +if mtype == 2: + print "CDMA modems do not support network scans" + sys.exit(1) + +print "Driver: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Driver')) +print "Modem device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'MasterDevice')) +print "Data device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Device')) +print "" + +net = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_GSM_NETWORK) +print "Scanning..." +try: + results = net.Scan(timeout=120) +except dbus.exceptions.DBusException, e: + print "Error scanning: %s" % e + results = {} + +for r in results: + status = r['status'] + if status == "1": + status = "available" + elif status == "2": + status = "current" + elif status == "3": + status = "forbidden" + else: + status = "(Unknown)" + + access_tech = "" + try: + access_tech_num = int(r['access-tech']) + access_tech = gsm_act[access_tech_num] + except KeyError: + pass + + opnum = "(%s):" % r['operator-num'] + # Extra space for 5-digit MCC/MNC + if r['operator-num'] == 5: + opnum += " " + + if r.has_key('operator-long') and len(r['operator-long']): + print "%s %s %s %s" % (r['operator-long'], opnum, status, access_tech) + elif r.has_key('operator-short') and len(r['operator-short']): + print "%s %s %s %s" % (r['operator-short'], opnum, status, access_tech) + else: + print "%s: %s %s" % (r['operator-num'], status, access_tech) + diff --git a/test/send-pin.py b/test/send-pin.py index 3cf47ee..002f1b0 100755 --- a/test/send-pin.py +++ b/test/send-pin.py @@ -33,7 +33,11 @@ if not sys.argv[2].isdigit(): os._exit(1) bus = dbus.SystemBus() -proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1]) +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/" + str(objpath) +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) + props = dbus.Interface(proxy, dbus_interface=DBUS_INTERFACE_PROPS) req = props.Get(MM_DBUS_INTERFACE_MODEM, "UnlockRequired") if req == "": diff --git a/test/sms-get.py b/test/sms-get.py new file mode 100755 index 0000000..981fb5d --- /dev/null +++ b/test/sms-get.py @@ -0,0 +1,80 @@ +#!/usr/bin/python +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details: +# +# Copyright (C) 2009 Novell, Inc. +# Copyright (C) 2009 - 2012 Red Hat, Inc. +# + +# An example on how to read SMS messages using ModemManager + +import sys +import dbus +import os + +MM_DBUS_SERVICE='org.freedesktop.ModemManager' +MM_DBUS_PATH='/org/freedesktop/ModemManager' +MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem' +MM_DBUS_INTERFACE_MODEM_SMS='org.freedesktop.ModemManager.Modem.Gsm.SMS' + +arglen = len(sys.argv) +if arglen != 2 and arglen != 3: + print "Usage: %s [message #]" % sys.argv[0] + sys.exit(1) + +msgnum = None +if len(sys.argv) == 3: + msgnum = int(sys.argv[2]) + +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/" + str(objpath) + +# Create the modem properties proxy +bus = dbus.SystemBus() +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) +modem = dbus.Interface(proxy, dbus_interface="org.freedesktop.DBus.Properties") + +# Make sure the modem is enabled first +if modem.Get(MM_DBUS_INTERFACE_MODEM, "Enabled") == False: + print "Modem is not enabled" + sys.exit(1) + +# Create the SMS interface proxy +sms = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_SMS) + +msgs = sms.List() +i = 0 +for m in msgs: + print "-------------------------------------------------------------------" + smsc = "" + try: + smsc = m["smsc"] + except KeyError: + pass + + print "%d: From: %s Time: %s SMSC: %s" % (m["index"], m["number"], m["timestamp"], smsc) + if len(m["text"]): + print " %s\n" % m["text"] + elif len(m["data"]): + print " Coding: %d" % m["data-coding-scheme"] + z = 1 + s = "" + for c in m["data"]: + s += "%02X " % c + if not z % 16: + print " %s" % s + s = "" + z += 1 + if len(s): + print " %s" % s + i += 1 + diff --git a/test/sms-send.py b/test/sms-send.py new file mode 100755 index 0000000..5977c20 --- /dev/null +++ b/test/sms-send.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details: +# +# Copyright (C) 2009 Novell, Inc. +# + +# An example on how to send an SMS message using ModemManager + +import sys +import dbus +import os + +arglen = len(sys.argv) +if arglen != 4 and arglen != 6 and arglen != 8: + print "Usage: %s --number [--smsc ] [--validity ] " % sys.argv[0] + sys.exit(1) + +number = None +validity = None +smsc = None +message = None +x = 1 +while x < arglen - 1: + if sys.argv[x] == "--number": + x += 1 + number = sys.argv[x].strip() + elif sys.argv[x] == "--validity": + x += 1 + validity = int(sys.argv[x]) + elif sys.argv[x] == "--smsc": + x += 1 + smsc = sys.argv[x].strip() + else: + raise ValueError("Unknown option '%s'" % sys.argv[x]) + x += 1 + +try: + lang = os.getenv("LANG") + idx = lang.find(".") + if idx != -1: + lang = lang[idx + 1:] +except KeyError: + lang = "utf-8" +message = unicode(sys.argv[arglen - 1], "utf-8") + + +bus = dbus.SystemBus() + +manager_proxy = bus.get_object('org.freedesktop.ModemManager', '/org/freedesktop/ModemManager') +manager_iface = dbus.Interface(manager_proxy, dbus_interface='org.freedesktop.ModemManager') +modems = manager_iface.EnumerateDevices() +if len(modems) == 0: + print "No modems found" + sys.exit(1) + +proxy = bus.get_object('org.freedesktop.ModemManager', modems[0]) +modem = dbus.Interface(proxy, dbus_interface='org.freedesktop.ModemManager.Modem') +modem.Enable(True) + +msg_dict = dbus.Dictionary( + { + dbus.String('number') : dbus.String(number), + dbus.String('text') : dbus.String(message) + }, + signature=dbus.Signature("sv") +) + +if smsc: + msg_dict[dbus.String('smsc')] = dbus.String(smsc) + +if validity: + msg_dict[dbus.String('validity')] = dbus.UInt32(validity) + +sms_iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.ModemManager.Modem.Gsm.SMS') +try: + indexes = sms_iface.Send(msg_dict) + print "Message index: %d" % indexes[0] +except Exception, e: + print "Sending message failed: %s" % e + diff --git a/test/ussd.py b/test/ussd.py new file mode 100755 index 0000000..73b8f8e --- /dev/null +++ b/test/ussd.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details: +# +# Copyright (C) 2010 Guido Guenther +# +# Usage: ./test/ussd.py /org/freedesktop/ModemManager/Modems/0 '*130#' + +import sys, dbus, re + +MM_DBUS_SERVICE='org.freedesktop.ModemManager' +MM_DBUS_INTERFACE_USSD='org.freedesktop.ModemManager.Modem.Gsm.Ussd' + +if len(sys.argv) != 3: + print "Usage: %s dbus_object [|cancel]" % sys.argv[0] + sys.exit(1) +else: + arg = sys.argv[2] + +bus = dbus.SystemBus() +objpath = sys.argv[1] +if objpath[:1] != '/': + objpath = "/org/freedesktop/ModemManager/Modems/" + str(objpath) +proxy = bus.get_object(MM_DBUS_SERVICE, objpath) + +modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_USSD) + +# For testing purposes treat all "common" USSD sequences as initiate and the +# rest (except for cancel) as response. See GSM 02.90. +initiate_re = re.compile('[*#]{1,3}1[0-9][0-9].*#') + +if initiate_re.match(arg): + ret = modem.Initiate(arg) +elif arg == "cancel": + ret = modem.Cancel() +else: + ret = modem.Respond(arg) +print ret + -- cgit v1.2.3