/*********************************************************************
 *
 * $Id: yocto_messagebox.cpp 72410 2026-03-11 07:18:41Z mvuilleu $
 *
 * Implements yFindMessageBox(), the high-level API for MessageBox functions
 *
 * - - - - - - - - - License information: - - - - - - - - -
 *
 *  Copyright (C) 2011 and beyond by Yoctopuce Sarl, Switzerland.
 *
 *  Yoctopuce Sarl (hereafter Licensor) grants to you a perpetual
 *  non-exclusive license to use, modify, copy and integrate this
 *  file into your software for the sole purpose of interfacing
 *  with Yoctopuce products.
 *
 *  You may reproduce and distribute copies of this file in
 *  source or object form, as long as the sole purpose of this
 *  code is to interface with Yoctopuce products. You must retain
 *  this notice in the distributed source file.
 *
 *  You should refer to Yoctopuce General Terms and Conditions
 *  for additional information regarding your rights and
 *  obligations.
 *
 *  THE SOFTWARE AND DOCUMENTATION ARE PROVIDED 'AS IS' WITHOUT
 *  WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
 *  WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS
 *  FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO
 *  EVENT SHALL LICENSOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
 *  INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
 *  COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR
 *  SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT
 *  LIMITED TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR
 *  CONTRIBUTION, OR OTHER SIMILAR COSTS, WHETHER ASSERTED ON THE
 *  BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF
 *  WARRANTY, OR OTHERWISE.
 *
 *********************************************************************/


#define _CRT_SECURE_NO_DEPRECATE //do not use windows secure crt
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

#include "yocto_messagebox.h"
#include "yapi/yproto.h"
#include "yapi/yjson.h"
#include "yapi/yapi.h"
#define  __FILE_ID__  "messagebox"

#ifdef YOCTOLIB_NAMESPACE
using namespace YOCTOLIB_NAMESPACE;
#endif

YSms::YSms(void):
//--- (generated code: YSms initialization)
    _mbox(NULL)
    ,_slot(0)
    ,_deliv(0)
    ,_isnew(0)
    ,_smsc("")
    ,_mref(0)
    ,_orig("")
    ,_dest("")
    ,_pid(0)
    ,_alphab(0)
    ,_mclass(0)
    ,_stamp("")
    ,_npdu(0)
    ,_aggSig("")
    ,_aggIdx(0)
    ,_aggCnt(0)
//--- (end of generated code: YSms initialization)
{ }

YSms::YSms(YMessageBox *mbox) :
//--- (generated code: YSms initialization)
    _mbox(NULL)
    ,_slot(0)
    ,_deliv(0)
    ,_isnew(0)
    ,_smsc("")
    ,_mref(0)
    ,_orig("")
    ,_dest("")
    ,_pid(0)
    ,_alphab(0)
    ,_mclass(0)
    ,_stamp("")
    ,_npdu(0)
    ,_aggSig("")
    ,_aggIdx(0)
    ,_aggCnt(0)
//--- (end of generated code: YSms initialization)
{
    _mbox = mbox;
}

//--- (generated code: YSms implementation)
// static attributes


int YSms::get_slot(void)
{
    return _slot;
}

string YSms::get_smsc(void)
{
    return _smsc;
}

int YSms::get_msgRef(void)
{
    return _mref;
}

int YSms::get_protocolId(void)
{
    return _pid;
}

string YSms::get_recipient(void)
{
    return _dest;
}

bool YSms::isNew(void)
{
    return _isnew;
}

bool YSms::isReceived(void)
{
    return _deliv;
}

int YSms::get_alphabet(void)
{
    return _alphab;
}

int YSms::get_msgClass(void)
{
    if ((_mclass & 16) == 0) {
        return -1;
    }
    return (_mclass & 3);
}

int YSms::get_dcs(void)
{
    return (_mclass | (_alphab << 2));
}

string YSms::get_userDataHeader(void)
{
    return _udh;
}

string YSms::get_userData(void)
{
    return _udata;
}

/**
 * Returns true iff the message is a "Flash" SMS (class 0 message). Flash messages
 * are displayed on the handset immediately and usually not saved on the SIM card.
 *
 * @return a boolean.
 */
bool YSms::isFlashMessage(void)
{
    return this->get_msgClass() == 0;
}

/**
 * Returns the reported message timestamp.
 *
 * @return the timestamp as a text string.
 */
string YSms::get_timestamp(void)
{
    return _stamp;
}

/**
 * Returns the reported message sender.
 *
 * @return a text string.
 */
string YSms::get_sender(void)
{
    return _orig;
}

/**
 * Returns the content of the message as a text string.
 *
 * @return a string with the content of the message.
 */
string YSms::get_textData(void)
{
    string isolatin;
    int isosize = 0;
    int i = 0;
    if (_alphab == 0) {
        // using GSM standard 7-bit alphabet
        return _mbox->gsm2str(_udata);
    }
    if (_alphab == 2) {
        // using UCS-2 alphabet
        isosize = ((int)(_udata).size() >> 1);
        isolatin = string(isosize, (char)0);
        i = 0;
        while (i < isosize) {
            isolatin[i] = (char)(((u8)_udata[2*i+1]));
            i = i + 1;
        }
        return isolatin;
    }
    // default: convert 8 bit to string as-is
    return _udata;
}

/**
 * Returns the content of the message, as a list of integer unicode values.
 *
 * @return a list of integers.
 */
vector<int> YSms::get_unicodeData(void)
{
    vector<int> res;
    int unisize = 0;
    int unival = 0;
    int i = 0;
    if (_alphab == 0) {
        // using GSM standard 7-bit alphabet
        return _mbox->gsm2unicode(_udata);
    }
    if (_alphab == 2) {
        // using UCS-2 alphabet
        unisize = ((int)(_udata).size() >> 1);
        res.clear();
        i = 0;
        while (i < unisize) {
            unival = 256*((u8)_udata[2*i])+((u8)_udata[2*i+1]);
            res.push_back(unival);
            i = i + 1;
        }
    } else {
        // return straight 8-bit values
        unisize = (int)(_udata).size();
        res.clear();
        i = 0;
        while (i < unisize) {
            res.push_back(((u8)_udata[i])+0);
            i = i + 1;
        }
    }
    return res;
}

int YSms::get_partCount(void)
{
    if (_npdu == 0) {
        this->generatePdu();
    }
    return _npdu;
}

string YSms::get_pdu(void)
{
    if (_npdu == 0) {
        this->generatePdu();
    }
    return _pdu;
}

vector<YSms> YSms::get_parts(void)
{
    if (_npdu == 0) {
        this->generatePdu();
    }
    return _parts;
}

string YSms::get_concatSignature(void)
{
    if (_npdu == 0) {
        this->generatePdu();
    }
    return _aggSig;
}

int YSms::get_concatIndex(void)
{
    if (_npdu == 0) {
        this->generatePdu();
    }
    return _aggIdx;
}

int YSms::get_concatCount(void)
{
    if (_npdu == 0) {
        this->generatePdu();
    }
    return _aggCnt;
}

int YSms::set_slot(int val)
{
    _slot = val;
    return YAPI_SUCCESS;
}

int YSms::set_received(bool val)
{
    _deliv = val;
    return YAPI_SUCCESS;
}

int YSms::set_new(bool val)
{
    _isnew = val;
    return YAPI_SUCCESS;
}

int YSms::set_smsc(string val)
{
    _smsc = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_msgRef(int val)
{
    _mref = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_sender(string val)
{
    _orig = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_recipient(string val)
{
    _dest = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_protocolId(int val)
{
    _pid = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_alphabet(int val)
{
    _alphab = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_msgClass(int val)
{
    if (val == -1) {
        _mclass = 0;
    } else {
        _mclass = 16+val;
    }
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_dcs(int val)
{
    _alphab = ((val >> 2) & 3);
    _mclass = (val & (16+3));
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_timestamp(string val)
{
    _stamp = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::set_userDataHeader(string val)
{
    _udh = val;
    _npdu = 0;
    this->parseUserDataHeader();
    return YAPI_SUCCESS;
}

int YSms::set_userData(string val)
{
    _udata = val;
    _npdu = 0;
    return YAPI_SUCCESS;
}

int YSms::convertToUnicode(void)
{
    vector<int> ucs2;
    int udatalen = 0;
    int i = 0;
    int uni = 0;
    if (_alphab == 2) {
        return YAPI_SUCCESS;
    }
    if (_alphab == 0) {
        ucs2 = _mbox->gsm2unicode(_udata);
    } else {
        udatalen = (int)(_udata).size();
        ucs2.clear();
        i = 0;
        while (i < udatalen) {
            uni = ((u8)_udata[i]);
            ucs2.push_back(uni);
            i = i + 1;
        }
    }
    _alphab = 2;
    _udata = string(0, (char)0);
    this->addUnicodeData(ucs2);
    return YAPI_SUCCESS;
}

/**
 * Adds regular text to the SMS. This function support messages
 * of more than 160 characters. ISO-latin accented characters
 * are supported. For messages with special unicode characters such as asian
 * characters and emoticons, use the  addUnicodeData method.
 *
 * @param val : the text to be sent in the message
 *
 * @return YAPI::SUCCESS when the call succeeds.
 */
int YSms::addText(string val)
{
    string udata;
    int udatalen = 0;
    string newdata;
    int newdatalen = 0;
    int i = 0;
    if ((int)(val).length() == 0) {
        return YAPI_SUCCESS;
    }
    if (_alphab == 0) {
        // Try to append using GSM 7-bit alphabet
        newdata = _mbox->str2gsm(val);
        newdatalen = (int)(newdata).size();
        if (newdatalen == 0) {
            // 7-bit not possible, switch to unicode
            this->convertToUnicode();
            newdata = val;
            newdatalen = (int)(newdata).size();
        }
    } else {
        newdata = val;
        newdatalen = (int)(newdata).size();
    }
    udatalen = (int)(_udata).size();
    if (_alphab == 2) {
        // Append in unicode directly
        udata = string(udatalen + 2*newdatalen, (char)0);
        i = 0;
        while (i < udatalen) {
            udata[i] = (char)(((u8)_udata[i]));
            i = i + 1;
        }
        i = 0;
        while (i < newdatalen) {
            udata[udatalen+1] = (char)(((u8)newdata[i]));
            udatalen = udatalen + 2;
            i = i + 1;
        }
    } else {
        // Append binary buffers
        udata = string(udatalen+newdatalen, (char)0);
        i = 0;
        while (i < udatalen) {
            udata[i] = (char)(((u8)_udata[i]));
            i = i + 1;
        }
        i = 0;
        while (i < newdatalen) {
            udata[udatalen] = (char)(((u8)newdata[i]));
            udatalen = udatalen + 1;
            i = i + 1;
        }
    }
    return this->set_userData(udata);
}

/**
 * Adds unicode characters to the SMS. This function support messages
 * of more than 160 characters, using SMS concatenation.
 *
 * @param val : a list of unicode characters provided as integers
 *
 * @return YAPI::SUCCESS when the call succeeds.
 */
int YSms::addUnicodeData(vector<int> val)
{
    int arrlen = 0;
    int newdatalen = 0;
    int i = 0;
    int uni = 0;
    string udata;
    int udatalen = 0;
    int surrogate = 0;
    if (_alphab != 2) {
        this->convertToUnicode();
    }
    // compute number of 16-bit code units
    arrlen = (int)val.size();
    newdatalen = arrlen;
    i = 0;
    while (i < arrlen) {
        uni = val[i];
        if (uni > 65535) {
            newdatalen = newdatalen + 1;
        }
        i = i + 1;
    }
    // now build utf-16 buffer
    udatalen = (int)(_udata).size();
    udata = string(udatalen+2*newdatalen, (char)0);
    i = 0;
    while (i < udatalen) {
        udata[i] = (char)(((u8)_udata[i]));
        i = i + 1;
    }
    i = 0;
    while (i < arrlen) {
        uni = val[i];
        if (uni >= 65536) {
            surrogate = uni - 65536;
            uni = ((surrogate >> 10) & 1023) + 55296;
            udata[udatalen] = (char)((uni >> 8));
            udata[udatalen+1] = (char)((uni & 255));
            udatalen = udatalen + 2;
            uni = (surrogate & 1023) + 56320;
        }
        udata[udatalen] = (char)((uni >> 8));
        udata[udatalen+1] = (char)((uni & 255));
        udatalen = udatalen + 2;
        i = i + 1;
    }
    return this->set_userData(udata);
}

int YSms::set_pdu(string pdu)
{
    _pdu = pdu;
    _npdu = 1;
    return this->parsePdu(pdu);
}

int YSms::set_parts(vector<YSms> parts)
{
    vector<YSms> sorted;
    int partno = 0;
    int initpartno = 0;
    int i = 0;
    int retcode = 0;
    int totsize = 0;
    YSms subsms;
    string subdata;
    string res;
    _npdu = (int)parts.size();
    if (_npdu == 0) {
        return YAPI_INVALID_ARGUMENT;
    }
    sorted.clear();
    partno = 0;
    while (partno < _npdu) {
        initpartno = partno;
        i = 0;
        while (i < _npdu) {
            subsms = parts[i];
            if (subsms.get_concatIndex() == partno) {
                sorted.push_back(subsms);
                partno = partno + 1;
            }
            i = i + 1;
        }
        if (initpartno == partno) {
            partno = partno + 1;
        }
    }
    _parts = sorted;
    // inherit header fields from first part
    subsms = _parts[0];
    retcode = this->parsePdu(subsms.get_pdu());
    if (retcode != YAPI_SUCCESS) {
        return retcode;
    }
    _npdu = (int)sorted.size();
    // concatenate user data from all parts
    totsize = 0;
    partno = 0;
    while (partno < (int)_parts.size()) {
        subsms = _parts[partno];
        subdata = subsms.get_userData();
        totsize = totsize + (int)(subdata).size();
        partno = partno + 1;
    }
    res = string(totsize, (char)0);
    totsize = 0;
    partno = 0;
    while (partno < (int)_parts.size()) {
        subsms = _parts[partno];
        subdata = subsms.get_userData();
        i = 0;
        while (i < (int)(subdata).size()) {
            res[totsize] = (char)(((u8)subdata[i]));
            totsize = totsize + 1;
            i = i + 1;
        }
        partno = partno + 1;
    }
    _udata = res;
    return YAPI_SUCCESS;
}

string YSms::encodeAddress(string addr)
{
    string bytes;
    int srclen = 0;
    int numlen = 0;
    int i = 0;
    int val = 0;
    int digit = 0;
    string res;
    bytes = addr;
    srclen = (int)(bytes).size();
    numlen = 0;
    i = 0;
    while (i < srclen) {
        val = ((u8)bytes[i]);
        if ((val >= 48) && (val < 58)) {
            numlen = numlen + 1;
        }
        i = i + 1;
    }
    if (numlen == 0) {
        res = string(1, (char)0);
        res[0] = (char)(0);
        return res;
    }
    res = string(2+((numlen+1) >> 1), (char)0);
    res[0] = (char)(numlen);
    if (((u8)bytes[0]) == 43) {
        res[1] = (char)(145);
    } else {
        res[1] = (char)(129);
    }
    numlen = 4;
    digit = 0;
    i = 0;
    while (i < srclen) {
        val = ((u8)bytes[i]);
        if ((val >= 48) && (val < 58)) {
            if ((numlen & 1) == 0) {
                digit = val - 48;
            } else {
                res[(numlen >> 1)] = (char)(digit + 16*(val-48));
            }
            numlen = numlen + 1;
        }
        i = i + 1;
    }
    // pad with F if needed
    if ((numlen & 1) != 0) {
        res[(numlen >> 1)] = (char)(digit + 240);
    }
    return res;
}

string YSms::decodeAddress(string addr,int ofs,int siz)
{
    int addrType = 0;
    string gsm7;
    string res;
    int i = 0;
    int rpos = 0;
    int carry = 0;
    int nbits = 0;
    int byt = 0;
    if (siz == 0) {
        return "";
    }
    res = "";
    addrType = (((u8)addr[ofs]) & 112);
    if (addrType == 80) {
        // alphanumeric number
        siz = ((4*siz) / 7);
        gsm7 = string(siz, (char)0);
        rpos = 1;
        carry = 0;
        nbits = 0;
        i = 0;
        while (i < siz) {
            if (nbits == 7) {
                gsm7[i] = (char)(carry);
                carry = 0;
                nbits = 0;
            } else {
                byt = ((u8)addr[ofs+rpos]);
                rpos = rpos + 1;
                gsm7[i] = (char)((carry | ((byt << nbits) & 127)));
                carry = (byt >> (7 - nbits));
                nbits = nbits + 1;
            }
            i = i + 1;
        }
        return _mbox->gsm2str(gsm7);
    } else {
        // standard phone number
        if (addrType == 16) {
            res = "+";
        }
        siz = ((siz+1) >> 1);
        i = 0;
        while (i < siz) {
            byt = ((u8)addr[ofs+i+1]);
            res = YapiWrapper::ysprintf("%s%x%x",res.c_str(),(byt & 15),(byt >> 4));
            i = i + 1;
        }
        // remove padding digit if needed
        if ((((u8)addr[ofs+siz]) >> 4) == 15) {
            res = res.substr(0, (int)(res).length()-1);
        }
        return res;
    }
}

string YSms::encodeTimeStamp(string exp)
{
    int explen = 0;
    int i = 0;
    string res;
    int n = 0;
    string expasc;
    int v1 = 0;
    int v2 = 0;
    explen = (int)(exp).length();
    if (explen == 0) {
        res = string(0, (char)0);
        return res;
    }
    if (exp.substr(0, 1) == "+") {
        n = atoi((exp.substr(1, explen-1)).c_str());
        res = string(1, (char)0);
        if (n > 30*86400) {
            n = 192+((n+6*86400) / (7*86400));
        } else {
            if (n > 86400) {
                n = 166+((n+86399) / 86400);
            } else {
                if (n > 43200) {
                    n = 143+((n-43200+1799) / 1800);
                } else {
                    n = -1+((n+299) / 300);
                }
            }
        }
        if (n < 0) {
            n = 0;
        }
        res[0] = (char)(n);
        return res;
    }
    if (exp.substr(4, 1) == "-" || exp.substr(4, 1) == "/") {
        // ignore century
        exp = exp.substr(2, explen-2);
        explen = (int)(exp).length();
    }
    expasc = exp;
    res = string(7, (char)0);
    n = 0;
    i = 0;
    while ((i+1 < explen) && (n < 7)) {
        v1 = ((u8)expasc[i]);
        if ((v1 >= 48) && (v1 < 58)) {
            v2 = ((u8)expasc[i+1]);
            if ((v2 >= 48) && (v2 < 58)) {
                v1 = v1 - 48;
                v2 = v2 - 48;
                res[n] = (char)(((v2 << 4)) + v1);
                n = n + 1;
                i = i + 1;
            }
        }
        i = i + 1;
    }
    while (n < 7) {
        res[n] = (char)(0);
        n = n + 1;
    }
    if (i+2 < explen) {
        // convert for timezone in cleartext ISO format +/-nn:nn
        v1 = ((u8)expasc[i-3]);
        v2 = ((u8)expasc[i]);
        if (((v1 == 43) || (v1 == 45)) && (v2 == 58)) {
            v1 = ((u8)expasc[i+1]);
            v2 = ((u8)expasc[i+2]);
            if ((v1 >= 48) && (v1 < 58) && (v1 >= 48) && (v1 < 58)) {
                v1 = ((10*(v1 - 48)+(v2 - 48)) / 15);
                n = n - 1;
                v2 = 4 * ((u8)res[n]) + v1;
                if (((u8)expasc[i-3]) == 45) {
                    v2 = v2 + 128;
                }
                res[n] = (char)(v2);
            }
        }
    }
    return res;
}

string YSms::decodeTimeStamp(string exp,int ofs,int siz)
{
    int n = 0;
    string res;
    int i = 0;
    int byt = 0;
    string sign;
    string hh;
    string ss;
    if (siz < 1) {
        return "";
    }
    if (siz == 1) {
        n = ((u8)exp[ofs]);
        if (n < 144) {
            n = n * 300;
        } else {
            if (n < 168) {
                n = (n-143) * 1800;
            } else {
                if (n < 197) {
                    n = (n-166) * 86400;
                } else {
                    n = (n-192) * 7 * 86400;
                }
            }
        }
        return YapiWrapper::ysprintf("+%d",n);
    }
    res = "20";
    i = 0;
    while ((i < siz) && (i < 6)) {
        byt = ((u8)exp[ofs+i]);
        res = YapiWrapper::ysprintf("%s%x%x",res.c_str(),(byt & 15),(byt >> 4));
        if (i < 3) {
            if (i < 2) {
                res = YapiWrapper::ysprintf("%s-",res.c_str());
            } else {
                res = YapiWrapper::ysprintf("%s ",res.c_str());
            }
        } else {
            if (i < 5) {
                res = YapiWrapper::ysprintf("%s:",res.c_str());
            }
        }
        i = i + 1;
    }
    if (siz == 7) {
        byt = ((u8)exp[ofs+i]);
        sign = "+";
        if ((byt & 8) != 0) {
            byt = byt - 8;
            sign = "-";
        }
        byt = (10*((byt & 15))) + ((byt >> 4));
        hh = YapiWrapper::ysprintf("%d",(byt >> 2));
        ss = YapiWrapper::ysprintf("%d",15*((byt & 3)));
        if ((int)(hh).length()<2) {
            hh = YapiWrapper::ysprintf("0%s",hh.c_str());
        }
        if ((int)(ss).length()<2) {
            ss = YapiWrapper::ysprintf("0%s",ss.c_str());
        }
        res = YapiWrapper::ysprintf("%s%s%s:%s",res.c_str(),sign.c_str(),hh.c_str(),ss.c_str());
    }
    return res;
}

int YSms::udataSize(void)
{
    int res = 0;
    int udhsize = 0;
    udhsize = (int)(_udh).size();
    res = (int)(_udata).size();
    if (_alphab == 0) {
        if (udhsize > 0) {
            res = res + ((8 + 8*udhsize + 6) / 7);
        }
        res = ((res * 7 + 7) / 8);
    } else {
        if (udhsize > 0) {
            res = res + 1 + udhsize;
        }
    }
    return res;
}

string YSms::encodeUserData(void)
{
    int udsize = 0;
    int udlen = 0;
    int udhsize = 0;
    int udhlen = 0;
    string res;
    int i = 0;
    int wpos = 0;
    int carry = 0;
    int nbits = 0;
    int thi_b = 0;
    // nbits = number of bits in carry
    udsize = this->udataSize();
    udhsize = (int)(_udh).size();
    udlen = (int)(_udata).size();
    res = string(1+udsize, (char)0);
    udhlen = 0;
    nbits = 0;
    carry = 0;
    // 1. Encode UDL
    if (_alphab == 0) {
        // 7-bit encoding
        if (udhsize > 0) {
            udhlen = ((8 + 8*udhsize + 6) / 7);
            nbits = 7*udhlen - 8 - 8*udhsize;
        }
        res[0] = (char)(udhlen+udlen);
    } else {
        // 8-bit encoding
        res[0] = (char)(udsize);
    }
    // 2. Encode UDHL and UDL
    wpos = 1;
    if (udhsize > 0) {
        res[wpos] = (char)(udhsize);
        wpos = wpos + 1;
        i = 0;
        while (i < udhsize) {
            res[wpos] = (char)(((u8)_udh[i]));
            wpos = wpos + 1;
            i = i + 1;
        }
    }
    // 3. Encode UD
    if (_alphab == 0) {
        // 7-bit encoding
        i = 0;
        while (i < udlen) {
            if (nbits == 0) {
                carry = ((u8)_udata[i]);
                nbits = 7;
            } else {
                thi_b = ((u8)_udata[i]);
                res[wpos] = (char)((carry | ((thi_b << nbits) & 255)));
                wpos = wpos + 1;
                nbits = nbits - 1;
                carry = (thi_b >> (7 - nbits));
            }
            i = i + 1;
        }
        if (nbits > 0) {
            res[wpos] = (char)(carry);
        }
    } else {
        // 8-bit encoding
        i = 0;
        while (i < udlen) {
            res[wpos] = (char)(((u8)_udata[i]));
            wpos = wpos + 1;
            i = i + 1;
        }
    }
    return res;
}

int YSms::generateParts(void)
{
    int udhsize = 0;
    int udlen = 0;
    int mss = 0;
    int partno = 0;
    int partlen = 0;
    string newud;
    string newudh;
    YSms newpdu;
    int i = 0;
    int wpos = 0;
    udhsize = (int)(_udh).size();
    udlen = (int)(_udata).size();
    mss = 140 - 1 - 5 - udhsize;
    if (_alphab == 0) {
        mss = ((mss * 8 - 6) / 7);
    }
    _npdu = ((udlen+mss-1) / mss);
    _parts.clear();
    partno = 0;
    wpos = 0;
    while (wpos < udlen) {
        partno = partno + 1;
        newudh = string(5+udhsize, (char)0);
        newudh[0] = (char)(0);           // IEI: concatenated message
        newudh[1] = (char)(3);           // IEDL: 3 bytes
        newudh[2] = (char)(_mref);
        newudh[3] = (char)(_npdu);
        newudh[4] = (char)(partno);
        i = 0;
        while (i < udhsize) {
            newudh[5+i] = (char)(((u8)_udh[i]));
            i = i + 1;
        }
        if (wpos+mss < udlen) {
            partlen = mss;
        } else {
            partlen = udlen-wpos;
        }
        newud = string(partlen, (char)0);
        i = 0;
        while (i < partlen) {
            newud[i] = (char)(((u8)_udata[wpos]));
            wpos = wpos + 1;
            i = i + 1;
        }
        newpdu = YSms(_mbox);
        newpdu.set_received(this->isReceived());
        newpdu.set_smsc(this->get_smsc());
        newpdu.set_msgRef(this->get_msgRef());
        newpdu.set_sender(this->get_sender());
        newpdu.set_recipient(this->get_recipient());
        newpdu.set_protocolId(this->get_protocolId());
        newpdu.set_dcs(this->get_dcs());
        newpdu.set_timestamp(this->get_timestamp());
        newpdu.set_userDataHeader(newudh);
        newpdu.set_userData(newud);
        _parts.push_back(newpdu);
    }
    return YAPI_SUCCESS;
}

int YSms::generatePdu(void)
{
    string sca;
    string hdr;
    string addr;
    string stamp;
    string udata;
    int pdutyp = 0;
    int pdulen = 0;
    int i = 0;
    // Determine if the message can fit within a single PDU
    _parts.clear();
    if (this->udataSize() > 140) {
        // multiple PDU are needed
        _pdu = string(0, (char)0);
        return this->generateParts();
    }
    sca = this->encodeAddress(_smsc);
    if ((int)(sca).size() > 0) {
        sca[0] = (char)((int)(sca).size()-1);
    }
    stamp = this->encodeTimeStamp(_stamp);
    udata = this->encodeUserData();
    if (_deliv) {
        addr = this->encodeAddress(_orig);
        hdr = string(1, (char)0);
        pdutyp = 0;
    } else {
        addr = this->encodeAddress(_dest);
        _mref = _mbox->nextMsgRef();
        hdr = string(2, (char)0);
        hdr[1] = (char)(_mref);
        pdutyp = 1;
        if ((int)(stamp).size() > 0) {
            pdutyp = pdutyp + 16;
        }
        if ((int)(stamp).size() == 7) {
            pdutyp = pdutyp + 8;
        }
    }
    if ((int)(_udh).size() > 0) {
        pdutyp = pdutyp + 64;
    }
    hdr[0] = (char)(pdutyp);
    pdulen = (int)(sca).size()+(int)(hdr).size()+(int)(addr).size()+2+(int)(stamp).size()+(int)(udata).size();
    _pdu = string(pdulen, (char)0);
    pdulen = 0;
    i = 0;
    while (i < (int)(sca).size()) {
        _pdu[pdulen] = (char)(((u8)sca[i]));
        pdulen = pdulen + 1;
        i = i + 1;
    }
    i = 0;
    while (i < (int)(hdr).size()) {
        _pdu[pdulen] = (char)(((u8)hdr[i]));
        pdulen = pdulen + 1;
        i = i + 1;
    }
    i = 0;
    while (i < (int)(addr).size()) {
        _pdu[pdulen] = (char)(((u8)addr[i]));
        pdulen = pdulen + 1;
        i = i + 1;
    }
    _pdu[pdulen] = (char)(_pid);
    pdulen = pdulen + 1;
    _pdu[pdulen] = (char)(this->get_dcs());
    pdulen = pdulen + 1;
    i = 0;
    while (i < (int)(stamp).size()) {
        _pdu[pdulen] = (char)(((u8)stamp[i]));
        pdulen = pdulen + 1;
        i = i + 1;
    }
    i = 0;
    while (i < (int)(udata).size()) {
        _pdu[pdulen] = (char)(((u8)udata[i]));
        pdulen = pdulen + 1;
        i = i + 1;
    }
    _npdu = 1;
    return YAPI_SUCCESS;
}

int YSms::parseUserDataHeader(void)
{
    int udhlen = 0;
    int i = 0;
    int iei = 0;
    int ielen = 0;
    string sig;
    _aggSig = "";
    _aggIdx = 0;
    _aggCnt = 0;
    udhlen = (int)(_udh).size();
    i = 0;
    while (i+1 < udhlen) {
        iei = ((u8)_udh[i]);
        ielen = ((u8)_udh[i+1]);
        i = i + 2;
        if (i + ielen <= udhlen) {
            if ((iei == 0) && (ielen == 3)) {
                // concatenated SMS, 8-bit ref
                sig = YapiWrapper::ysprintf("%s-%s-%02x-%02x",_orig.c_str(),_dest.c_str(),_mref,((u8)_udh[i]));
                _aggSig = sig;
                _aggCnt = ((u8)_udh[i+1]);
                _aggIdx = ((u8)_udh[i+2]);
            }
            if ((iei == 8) && (ielen == 4)) {
                // concatenated SMS, 16-bit ref
                sig = YapiWrapper::ysprintf("%s-%s-%02x-%02x%02x",_orig.c_str(),_dest.c_str(),_mref,((u8)_udh[i]),((u8)_udh[i+1]));
                _aggSig = sig;
                _aggCnt = ((u8)_udh[i+2]);
                _aggIdx = ((u8)_udh[i+3]);
            }
        }
        i = i + ielen;
    }
    return YAPI_SUCCESS;
}

int YSms::parsePdu(string pdu)
{
    int rpos = 0;
    int addrlen = 0;
    int pdutyp = 0;
    int tslen = 0;
    int dcs = 0;
    int udlen = 0;
    int udhsize = 0;
    int udhlen = 0;
    int i = 0;
    int carry = 0;
    int nbits = 0;
    int thi_b = 0;
    _pdu = pdu;
    _npdu = 1;
    // parse meta-data
    _smsc = this->decodeAddress(pdu, 1, 2*(((u8)pdu[0])-1));
    rpos = 1+((u8)pdu[0]);
    pdutyp = ((u8)pdu[rpos]);
    rpos = rpos + 1;
    _deliv = ((pdutyp & 3) == 0);
    if (_deliv) {
        addrlen = ((u8)pdu[rpos]);
        rpos = rpos + 1;
        _orig = this->decodeAddress(pdu, rpos, addrlen);
        _dest = "";
        tslen = 7;
    } else {
        _mref = ((u8)pdu[rpos]);
        rpos = rpos + 1;
        addrlen = ((u8)pdu[rpos]);
        rpos = rpos + 1;
        _dest = this->decodeAddress(pdu, rpos, addrlen);
        _orig = "";
        if ((pdutyp & 16) != 0) {
            if ((pdutyp & 8) != 0) {
                tslen = 7;
            } else {
                tslen= 1;
            }
        } else {
            tslen = 0;
        }
    }
    rpos = rpos + ((addrlen+3) >> 1);
    _pid = ((u8)pdu[rpos]);
    rpos = rpos + 1;
    dcs = ((u8)pdu[rpos]);
    rpos = rpos + 1;
    _alphab = ((dcs >> 2) & 3);
    _mclass = (dcs & (16+3));
    _stamp = this->decodeTimeStamp(pdu, rpos, tslen);
    rpos = rpos + tslen;
    // parse user data (including udh)
    nbits = 0;
    carry = 0;
    udlen = ((u8)pdu[rpos]);
    rpos = rpos + 1;
    if ((pdutyp & 64) != 0) {
        udhsize = ((u8)pdu[rpos]);
        rpos = rpos + 1;
        _udh = string(udhsize, (char)0);
        i = 0;
        while (i < udhsize) {
            _udh[i] = (char)(((u8)pdu[rpos]));
            rpos = rpos + 1;
            i = i + 1;
        }
        if (_alphab == 0) {
            // 7-bit encoding
            udhlen = ((8 + 8*udhsize + 6) / 7);
            nbits = 7*udhlen - 8 - 8*udhsize;
            if (nbits > 0) {
                thi_b = ((u8)pdu[rpos]);
                rpos = rpos + 1;
                carry = (thi_b >> nbits);
                nbits = 8 - nbits;
            }
        } else {
            // byte encoding
            udhlen = 1+udhsize;
        }
        udlen = udlen - udhlen;
    } else {
        udhsize = 0;
        _udh = string(0, (char)0);
    }
    _udata = string(udlen, (char)0);
    if (_alphab == 0) {
        // 7-bit encoding
        i = 0;
        while (i < udlen) {
            if (nbits == 7) {
                _udata[i] = (char)(carry);
                carry = 0;
                nbits = 0;
            } else {
                thi_b = ((u8)pdu[rpos]);
                rpos = rpos + 1;
                _udata[i] = (char)((carry | ((thi_b << nbits) & 127)));
                carry = (thi_b >> (7 - nbits));
                nbits = nbits + 1;
            }
            i = i + 1;
        }
    } else {
        // 8-bit encoding
        i = 0;
        while (i < udlen) {
            _udata[i] = (char)(((u8)pdu[rpos]));
            rpos = rpos + 1;
            i = i + 1;
        }
    }
    this->parseUserDataHeader();
    return YAPI_SUCCESS;
}

/**
 * Sends the SMS to the recipient. Messages of more than 160 characters are supported
 * using SMS concatenation.
 *
 * @return YAPI::SUCCESS when the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YSms::send(void)
{
    int i = 0;
    int retcode = 0;
    YSms pdu;

    if (_npdu == 0) {
        this->generatePdu();
    }
    if (_npdu > 1) {
        // send multiple PDUs using recursive call
        retcode = YAPI_SUCCESS;
        i = 0;
        while ((i < _npdu) && (retcode == YAPI_SUCCESS)) {
            pdu = _parts[i];
            retcode= pdu.send();
            i = i + 1;
        }
        return retcode;
    }
    // send a single PDU
    return _mbox->sendPDU(_pdu);
}

/**
 * Delete the SMS from the SIM card.
 *
 * @return YAPI::SUCCESS when the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YSms::deleteFromSIM(void)
{
    int i = 0;
    int retcode = 0;
    YSms pdu;

    if (_npdu < 2) {
        return _mbox->clearSIMSlot(_slot);
    }
    retcode = YAPI_SUCCESS;
    i = 0;
    while ((i < _npdu) && (retcode == YAPI_SUCCESS)) {
        pdu = _parts[i];
        retcode= pdu.deleteFromSIM();
        i = i + 1;
    }
    return retcode;
}
//--- (end of generated code: YSms implementation)


YMessageBox::YMessageBox(const string& func): YFunction(func)
//--- (generated code: YMessageBox initialization)
    ,_slotsInUse(SLOTSINUSE_INVALID)
    ,_slotsCount(SLOTSCOUNT_INVALID)
    ,_slotsBitmap(SLOTSBITMAP_INVALID)
    ,_pduSent(PDUSENT_INVALID)
    ,_pduReceived(PDURECEIVED_INVALID)
    ,_obey(OBEY_INVALID)
    ,_command(COMMAND_INVALID)
    ,_valueCallbackMessageBox(NULL)
    ,_smsCallback(NULL)
    ,_nextMsgRef(0)
    ,_prevBitmapStr("")
    ,_gsm2unicodeReady(0)
//--- (end of generated code: YMessageBox initialization)
{
    _className="MessageBox";
}

YMessageBox::~YMessageBox()
{
//--- (generated code: YMessageBox cleanup)
//--- (end of generated code: YMessageBox cleanup)
}

//--- (generated code: YMessageBox implementation)
void YMessageBox::yInternalEventCallback(YMessageBox *obj, const string& value)
{
    obj->_internalEventHandler(value);
}

// static attributes
const string YMessageBox::SLOTSBITMAP_INVALID = YAPI_INVALID_STRING;
const string YMessageBox::OBEY_INVALID = YAPI_INVALID_STRING;
const string YMessageBox::COMMAND_INVALID = YAPI_INVALID_STRING;

int YMessageBox::_parseAttr(YJSONObject *json_val)
{
    if(json_val->has("slotsInUse")) {
        _slotsInUse =  json_val->getInt("slotsInUse");
    }
    if(json_val->has("slotsCount")) {
        _slotsCount =  json_val->getInt("slotsCount");
    }
    if(json_val->has("slotsBitmap")) {
        _slotsBitmap =  json_val->getString("slotsBitmap");
    }
    if(json_val->has("pduSent")) {
        _pduSent =  json_val->getInt("pduSent");
    }
    if(json_val->has("pduReceived")) {
        _pduReceived =  json_val->getInt("pduReceived");
    }
    if(json_val->has("obey")) {
        _obey =  json_val->getString("obey");
    }
    if(json_val->has("command")) {
        _command =  json_val->getString("command");
    }
    return YFunction::_parseAttr(json_val);
}


/**
 * Returns the number of message storage slots currently in use.
 *
 * @return an integer corresponding to the number of message storage slots currently in use
 *
 * On failure, throws an exception or returns YMessageBox::SLOTSINUSE_INVALID.
 */
int YMessageBox::get_slotsInUse(void)
{
    int res = 0;
    yEnterCriticalSection(&_this_cs);
    try {
        if (_cacheExpiration <= YAPI::GetTickCount()) {
            if (this->_load_unsafe(YAPI::_yapiContext.GetCacheValidity()) != YAPI_SUCCESS) {
                {
                    yLeaveCriticalSection(&_this_cs);
                    return YMessageBox::SLOTSINUSE_INVALID;
                }
            }
        }
        res = _slotsInUse;
    } catch (std::exception &) {
        yLeaveCriticalSection(&_this_cs);
        throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Returns the total number of message storage slots on the SIM card.
 *
 * @return an integer corresponding to the total number of message storage slots on the SIM card
 *
 * On failure, throws an exception or returns YMessageBox::SLOTSCOUNT_INVALID.
 */
int YMessageBox::get_slotsCount(void)
{
    int res = 0;
    yEnterCriticalSection(&_this_cs);
    try {
        if (_cacheExpiration <= YAPI::GetTickCount()) {
            if (this->_load_unsafe(YAPI::_yapiContext.GetCacheValidity()) != YAPI_SUCCESS) {
                {
                    yLeaveCriticalSection(&_this_cs);
                    return YMessageBox::SLOTSCOUNT_INVALID;
                }
            }
        }
        res = _slotsCount;
    } catch (std::exception &) {
        yLeaveCriticalSection(&_this_cs);
        throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

string YMessageBox::get_slotsBitmap(void)
{
    string res;
    yEnterCriticalSection(&_this_cs);
    try {
        if (_cacheExpiration <= YAPI::GetTickCount()) {
            if (this->_load_unsafe(YAPI::_yapiContext.GetCacheValidity()) != YAPI_SUCCESS) {
                {
                    yLeaveCriticalSection(&_this_cs);
                    return YMessageBox::SLOTSBITMAP_INVALID;
                }
            }
        }
        res = _slotsBitmap;
    } catch (std::exception &) {
        yLeaveCriticalSection(&_this_cs);
        throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Returns the number of SMS units sent so far.
 *
 * @return an integer corresponding to the number of SMS units sent so far
 *
 * On failure, throws an exception or returns YMessageBox::PDUSENT_INVALID.
 */
int YMessageBox::get_pduSent(void)
{
    int res = 0;
    yEnterCriticalSection(&_this_cs);
    try {
        if (_cacheExpiration <= YAPI::GetTickCount()) {
            if (this->_load_unsafe(YAPI::_yapiContext.GetCacheValidity()) != YAPI_SUCCESS) {
                {
                    yLeaveCriticalSection(&_this_cs);
                    return YMessageBox::PDUSENT_INVALID;
                }
            }
        }
        res = _pduSent;
    } catch (std::exception &) {
        yLeaveCriticalSection(&_this_cs);
        throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Changes the value of the outgoing SMS units counter.
 *
 * @param newval : an integer corresponding to the value of the outgoing SMS units counter
 *
 * @return YAPI::SUCCESS if the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YMessageBox::set_pduSent(int newval)
{
    string rest_val;
    int res;
    yEnterCriticalSection(&_this_cs);
    try {
        char buf[32]; SAFE_SPRINTF(buf, 32, "%d", newval); rest_val = string(buf);
        res = _setAttr("pduSent", rest_val);
    } catch (std::exception &) {
         yLeaveCriticalSection(&_this_cs);
         throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Returns the number of SMS units received so far.
 *
 * @return an integer corresponding to the number of SMS units received so far
 *
 * On failure, throws an exception or returns YMessageBox::PDURECEIVED_INVALID.
 */
int YMessageBox::get_pduReceived(void)
{
    int res = 0;
    yEnterCriticalSection(&_this_cs);
    try {
        if (_cacheExpiration <= YAPI::GetTickCount()) {
            if (this->_load_unsafe(YAPI::_yapiContext.GetCacheValidity()) != YAPI_SUCCESS) {
                {
                    yLeaveCriticalSection(&_this_cs);
                    return YMessageBox::PDURECEIVED_INVALID;
                }
            }
        }
        res = _pduReceived;
    } catch (std::exception &) {
        yLeaveCriticalSection(&_this_cs);
        throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Changes the value of the incoming SMS units counter.
 *
 * @param newval : an integer corresponding to the value of the incoming SMS units counter
 *
 * @return YAPI::SUCCESS if the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YMessageBox::set_pduReceived(int newval)
{
    string rest_val;
    int res;
    yEnterCriticalSection(&_this_cs);
    try {
        char buf[32]; SAFE_SPRINTF(buf, 32, "%d", newval); rest_val = string(buf);
        res = _setAttr("pduReceived", rest_val);
    } catch (std::exception &) {
         yLeaveCriticalSection(&_this_cs);
         throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Returns the phone number authorized to send remote management commands.
 * When a phone number is specified, the hub will take contre of all incoming
 * SMS messages: it will execute commands coming from the authorized number,
 * and delete all messages once received (whether authorized or not).
 * If you need to receive SMS messages using your own software, leave this
 * attribute empty.
 *
 * @return a string corresponding to the phone number authorized to send remote management commands
 *
 * On failure, throws an exception or returns YMessageBox::OBEY_INVALID.
 */
string YMessageBox::get_obey(void)
{
    string res;
    yEnterCriticalSection(&_this_cs);
    try {
        if (_cacheExpiration <= YAPI::GetTickCount()) {
            if (this->_load_unsafe(YAPI::_yapiContext.GetCacheValidity()) != YAPI_SUCCESS) {
                {
                    yLeaveCriticalSection(&_this_cs);
                    return YMessageBox::OBEY_INVALID;
                }
            }
        }
        res = _obey;
    } catch (std::exception &) {
        yLeaveCriticalSection(&_this_cs);
        throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Changes the phone number authorized to send remote management commands.
 * The phone number usually starts with a '+' and does not include spacers.
 * When a phone number is specified, the hub will take contre of all incoming
 * SMS messages: it will execute commands coming from the authorized number,
 * and delete all messages once received (whether authorized or not).
 * If you need to receive SMS messages using your own software, leave this
 * attribute empty. Remember to call the saveToFlash() method of the
 * module if the modification must be kept.
 *
 * This feature is only available since YoctoHub-GSM-4G.
 *
 * @param newval : a string corresponding to the phone number authorized to send remote management commands
 *
 * @return YAPI::SUCCESS if the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YMessageBox::set_obey(const string& newval)
{
    string rest_val;
    int res;
    yEnterCriticalSection(&_this_cs);
    try {
        rest_val = newval;
        res = _setAttr("obey", rest_val);
    } catch (std::exception &) {
         yLeaveCriticalSection(&_this_cs);
         throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

string YMessageBox::get_command(void)
{
    string res;
    yEnterCriticalSection(&_this_cs);
    try {
        if (_cacheExpiration <= YAPI::GetTickCount()) {
            if (this->_load_unsafe(YAPI::_yapiContext.GetCacheValidity()) != YAPI_SUCCESS) {
                {
                    yLeaveCriticalSection(&_this_cs);
                    return YMessageBox::COMMAND_INVALID;
                }
            }
        }
        res = _command;
    } catch (std::exception &) {
        yLeaveCriticalSection(&_this_cs);
        throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

int YMessageBox::set_command(const string& newval)
{
    string rest_val;
    int res;
    yEnterCriticalSection(&_this_cs);
    try {
        rest_val = newval;
        res = _setAttr("command", rest_val);
    } catch (std::exception &) {
         yLeaveCriticalSection(&_this_cs);
         throw;
    }
    yLeaveCriticalSection(&_this_cs);
    return res;
}

/**
 * Retrieves a SMS message box interface for a given identifier.
 * The identifier can be specified using several formats:
 *
 * - FunctionLogicalName
 * - ModuleSerialNumber.FunctionIdentifier
 * - ModuleSerialNumber.FunctionLogicalName
 * - ModuleLogicalName.FunctionIdentifier
 * - ModuleLogicalName.FunctionLogicalName
 *
 *
 * This function does not require that the SMS message box interface is online at the time
 * it is invoked. The returned object is nevertheless valid.
 * Use the method isOnline() to test if the SMS message box interface is
 * indeed online at a given time. In case of ambiguity when looking for
 * a SMS message box interface by logical name, no error is notified: the first instance
 * found is returned. The search is performed first by hardware name,
 * then by logical name.
 *
 * If a call to this object's is_online() method returns FALSE although
 * you are certain that the matching device is plugged, make sure that you did
 * call registerHub() at application initialization time.
 *
 * @param func : a string that uniquely characterizes the SMS message box interface, for instance
 *         YHUBGSM1.messageBox.
 *
 * @return a YMessageBox object allowing you to drive the SMS message box interface.
 */
YMessageBox* YMessageBox::FindMessageBox(string func)
{
    YMessageBox* obj = NULL;
    int taken = 0;
    if (YAPI::_apiInitialized) {
        yEnterCriticalSection(&YAPI::_global_cs);
        taken = 1;
    }try {
        obj = (YMessageBox*) YFunction::_FindFromCache("MessageBox", func);
        if (obj == NULL) {
            obj = new YMessageBox(func);
            YFunction::_AddToCache("MessageBox", func, obj);
        }
    } catch (std::exception &) {
        if (taken) yLeaveCriticalSection(&YAPI::_global_cs);
        throw;
    }
    if (taken) yLeaveCriticalSection(&YAPI::_global_cs);
    return obj;
}

/**
 * Registers the callback function that is invoked on every change of advertised value.
 * The callback is then invoked only during the execution of ySleep or yHandleEvents.
 * This provides control over the time when the callback is triggered. For good responsiveness,
 * remember to call one of these two functions periodically. The callback is called once juste after beeing
 * registered, passing the current advertised value  of the function, provided that it is not an empty string.
 * To unregister a callback, pass a NULL pointer as argument.
 *
 * @param callback : the callback function to call, or a NULL pointer. The callback function should take two
 *         arguments: the function object of which the value has changed, and the character string describing
 *         the new advertised value.
 * @noreturn
 */
int YMessageBox::registerValueCallback(YMessageBoxValueCallback callback)
{
    string val;
    if (callback != NULL) {
        YFunction::_UpdateValueCallbackList(this, true);
    } else {
        YFunction::_UpdateValueCallbackList(this, false);
    }
    _valueCallbackMessageBox = callback;
    // Immediately invoke value callback with current value
    if (callback != NULL && this->isOnline()) {
        val = _advertisedValue;
        if (!(val == "")) {
            this->_invokeValueCallback(val);
        }
    }
    return 0;
}

int YMessageBox::_invokeValueCallback(string value)
{
    if (_valueCallbackMessageBox != NULL) {
        _valueCallbackMessageBox(this, value);
    } else {
        YFunction::_invokeValueCallback(value);
    }
    return 0;
}

int YMessageBox::nextMsgRef(void)
{
    _nextMsgRef = _nextMsgRef + 1;
    return _nextMsgRef;
}

int YMessageBox::clearSIMSlot(int slot)
{
    int retry = 0;
    int idx = 0;
    string bitmapStr;
    int int_res = 0;
    string newBitmap;
    int bitVal = 0;

    retry = 5;
    while (retry > 0) {
        this->clearCache();
        bitmapStr = this->get_slotsBitmap();
        newBitmap = YAPI::_hexStr2Bin(bitmapStr);
        idx = (slot >> 3);
        if (idx < (int)(newBitmap).size()) {
            bitVal = (1 << (slot & 7));
            if ((((u8)newBitmap[idx]) & bitVal) != 0) {
                _prevBitmapStr = "";
                int_res = this->set_command(YapiWrapper::ysprintf("DS%d",slot));
                if (int_res < 0) {
                    return int_res;
                }
            } else {
                return YAPI_SUCCESS;
            }
        } else {
            return YAPI_INVALID_ARGUMENT;
        }
        this->_download("at.txt?cmd=");
        retry = retry - 1;
    }
    return YAPI_IO_ERROR;
}

int YMessageBox::sendPDU(string pdu)
{
    int i = 0;
    string buff;
    int bufflen = 0;
    string buffstr;
    string res;
    int waitMore = 0;
    string cmd;

    buff = this->_uploadEx("sendSMS", pdu);
    if ((int)(buff).size() < 2) {
        return YAPI_SUCCESS;
    }
    if (((u8)buff[0]) != 64) {
        return YAPI_SUCCESS;
    }
    // new firmware provides a way to check result of SMS send command
    res = "";
    bufflen = (int)(buff).size();
    buffstr = buff;
    i = 0;
    waitMore = 10;
    while (waitMore > 0) {
        cmd = YapiWrapper::ysprintf("at.txt?cmd=%s",buffstr.substr(i, bufflen - i).c_str());
        buff = this->_download(cmd);
        bufflen = (int)(buff).size();
        buffstr = buff;
        i = bufflen - 1;
        while ((i > 0) && (((u8)buff[i]) != 64) && (((u8)buff[i]) != 10) && (((u8)buff[i]) != 13)) {
            i = i - 1;
        }
        if ((i >= 0) && (((u8)buff[i]) == 64)) {
            // continuation detected
            waitMore = waitMore - 1;
        } else {
            // request complete
            waitMore = 0;
        }
        res = YapiWrapper::ysprintf("%s%s",res.c_str(),buffstr.substr(0, i).c_str());
    }
    if (!(_ystrpos(res, "OK") >= 0)) {
        _throw((YRETCODE)(YAPI_NOT_SUPPORTED), "Failed to send SMS");
        return YAPI_NOT_SUPPORTED;
    }
    return YAPI_SUCCESS;
}

YSms YMessageBox::fetchPdu(int slot)
{
    string binPdu;
    vector<string> arrPdu;
    string hexPdu;
    YSms sms;
    sms = YSms(this);
    sms.set_slot(slot);

    binPdu = this->_download(YapiWrapper::ysprintf("sms.json?pos=%d&len=1",slot));
    if ((int)(binPdu).size()<8) {
        // Retry in case SIM was busy
        {string ignore_error; YAPI::Sleep(250, ignore_error);};
        binPdu = this->_download(YapiWrapper::ysprintf("sms.json?pos=%d&len=1",slot));
        if (!((int)(binPdu).size()>=8)) {
            _throw((YRETCODE)(YAPI_IO_ERROR), "unable to retrieve SMS");
            return sms;
        }
    }
    arrPdu = this->_json_get_array(binPdu);
    hexPdu = this->_decode_json_string(arrPdu[0]);
    sms.parsePdu(YAPI::_hexStr2Bin(hexPdu));
    return sms;
}

int YMessageBox::initGsm2Unicode(void)
{
    int i = 0;
    int uni = 0;
    _gsm2unicode.clear();
    // 00-07
    _gsm2unicode.push_back(64);
    _gsm2unicode.push_back(163);
    _gsm2unicode.push_back(36);
    _gsm2unicode.push_back(165);
    _gsm2unicode.push_back(232);
    _gsm2unicode.push_back(233);
    _gsm2unicode.push_back(249);
    _gsm2unicode.push_back(236);
    // 08-0F
    _gsm2unicode.push_back(242);
    _gsm2unicode.push_back(199);
    _gsm2unicode.push_back(10);
    _gsm2unicode.push_back(216);
    _gsm2unicode.push_back(248);
    _gsm2unicode.push_back(13);
    _gsm2unicode.push_back(197);
    _gsm2unicode.push_back(229);
    // 10-17
    _gsm2unicode.push_back(916);
    _gsm2unicode.push_back(95);
    _gsm2unicode.push_back(934);
    _gsm2unicode.push_back(915);
    _gsm2unicode.push_back(923);
    _gsm2unicode.push_back(937);
    _gsm2unicode.push_back(928);
    _gsm2unicode.push_back(936);
    // 18-1F
    _gsm2unicode.push_back(931);
    _gsm2unicode.push_back(920);
    _gsm2unicode.push_back(926);
    _gsm2unicode.push_back(27);
    _gsm2unicode.push_back(198);
    _gsm2unicode.push_back(230);
    _gsm2unicode.push_back(223);
    _gsm2unicode.push_back(201);
    // 20-7A
    i = 32;
    while (i <= 122) {
        _gsm2unicode.push_back(i);
        i = i + 1;
    }
    // exceptions in range 20-7A
    _gsm2unicode[36] = 164;
    _gsm2unicode[64] = 161;
    _gsm2unicode[91] = 196;
    _gsm2unicode[92] = 214;
    _gsm2unicode[93] = 209;
    _gsm2unicode[94] = 220;
    _gsm2unicode[95] = 167;
    _gsm2unicode[96] = 191;
    // 7B-7F
    _gsm2unicode.push_back(228);
    _gsm2unicode.push_back(246);
    _gsm2unicode.push_back(241);
    _gsm2unicode.push_back(252);
    _gsm2unicode.push_back(224);
    // Invert table as well wherever possible
    _iso2gsm = string(256, (char)0);
    i = 0;
    while (i <= 127) {
        uni = _gsm2unicode[i];
        if (uni <= 255) {
            _iso2gsm[uni] = (char)(i);
        }
        i = i + 1;
    }
    i = 0;
    while (i < 4) {
        // mark escape sequences
        _iso2gsm[91+i] = (char)(27);
        _iso2gsm[123+i] = (char)(27);
        i = i + 1;
    }
    // Done
    _gsm2unicodeReady = true;
    return YAPI_SUCCESS;
}

vector<int> YMessageBox::gsm2unicode(string gsm)
{
    int i = 0;
    int gsmlen = 0;
    int reslen = 0;
    vector<int> res;
    int uni = 0;
    if (!(_gsm2unicodeReady)) {
        this->initGsm2Unicode();
    }
    gsmlen = (int)(gsm).size();
    reslen = gsmlen;
    i = 0;
    while (i < gsmlen) {
        if (((u8)gsm[i]) == 27) {
            reslen = reslen - 1;
        }
        i = i + 1;
    }
    res.clear();
    i = 0;
    while (i < gsmlen) {
        uni = _gsm2unicode[((u8)gsm[i])];
        if ((uni == 27) && (i+1 < gsmlen)) {
            i = i + 1;
            uni = ((u8)gsm[i]);
            if (uni < 60) {
                if (uni < 41) {
                    if (uni==20) {
                        uni=94;
                    } else {
                        if (uni==40) {
                            uni=123;
                        } else {
                            uni=0;
                        }
                    }
                } else {
                    if (uni==41) {
                        uni=125;
                    } else {
                        if (uni==47) {
                            uni=92;
                        } else {
                            uni=0;
                        }
                    }
                }
            } else {
                if (uni < 62) {
                    if (uni==60) {
                        uni=91;
                    } else {
                        if (uni==61) {
                            uni=126;
                        } else {
                            uni=0;
                        }
                    }
                } else {
                    if (uni==62) {
                        uni=93;
                    } else {
                        if (uni==64) {
                            uni=124;
                        } else {
                            if (uni==101) {
                                uni=164;
                            } else {
                                uni=0;
                            }
                        }
                    }
                }
            }
        }
        if (uni > 0) {
            res.push_back(uni);
        }
        i = i + 1;
    }
    return res;
}

string YMessageBox::gsm2str(string gsm)
{
    int i = 0;
    int gsmlen = 0;
    int reslen = 0;
    string resbin;
    string resstr;
    int uni = 0;
    if (!(_gsm2unicodeReady)) {
        this->initGsm2Unicode();
    }
    gsmlen = (int)(gsm).size();
    reslen = gsmlen;
    i = 0;
    while (i < gsmlen) {
        if (((u8)gsm[i]) == 27) {
            reslen = reslen - 1;
        }
        i = i + 1;
    }
    resbin = string(reslen, (char)0);
    i = 0;
    reslen = 0;
    while (i < gsmlen) {
        uni = _gsm2unicode[((u8)gsm[i])];
        if ((uni == 27) && (i+1 < gsmlen)) {
            i = i + 1;
            uni = ((u8)gsm[i]);
            if (uni < 60) {
                if (uni < 41) {
                    if (uni==20) {
                        uni=94;
                    } else {
                        if (uni==40) {
                            uni=123;
                        } else {
                            uni=0;
                        }
                    }
                } else {
                    if (uni==41) {
                        uni=125;
                    } else {
                        if (uni==47) {
                            uni=92;
                        } else {
                            uni=0;
                        }
                    }
                }
            } else {
                if (uni < 62) {
                    if (uni==60) {
                        uni=91;
                    } else {
                        if (uni==61) {
                            uni=126;
                        } else {
                            uni=0;
                        }
                    }
                } else {
                    if (uni==62) {
                        uni=93;
                    } else {
                        if (uni==64) {
                            uni=124;
                        } else {
                            if (uni==101) {
                                uni=164;
                            } else {
                                uni=0;
                            }
                        }
                    }
                }
            }
        }
        if ((uni > 0) && (uni < 256)) {
            resbin[reslen] = (char)(uni);
            reslen = reslen + 1;
        }
        i = i + 1;
    }
    resstr = resbin;
    if ((int)(resstr).length() > reslen) {
        resstr = resstr.substr(0, reslen);
    }
    return resstr;
}

string YMessageBox::str2gsm(string msg)
{
    string asc;
    int asclen = 0;
    int i = 0;
    int ch = 0;
    int gsm7 = 0;
    int extra = 0;
    string res;
    int wpos = 0;
    if (!(_gsm2unicodeReady)) {
        this->initGsm2Unicode();
    }
    asc = msg;
    asclen = (int)(asc).size();
    extra = 0;
    i = 0;
    while (i < asclen) {
        ch = ((u8)asc[i]);
        gsm7 = ((u8)_iso2gsm[ch]);
        if (gsm7 == 27) {
            extra = extra + 1;
        }
        if (gsm7 == 0) {
            // cannot use standard GSM encoding
            res = string(0, (char)0);
            return res;
        }
        i = i + 1;
    }
    res = string(asclen+extra, (char)0);
    wpos = 0;
    i = 0;
    while (i < asclen) {
        ch = ((u8)asc[i]);
        gsm7 = ((u8)_iso2gsm[ch]);
        res[wpos] = (char)(gsm7);
        wpos = wpos + 1;
        if (gsm7 == 27) {
            if (ch < 100) {
                if (ch<93) {
                    if (ch<92) {
                        gsm7=60;
                    } else {
                        gsm7=47;
                    }
                } else {
                    if (ch<94) {
                        gsm7=62;
                    } else {
                        gsm7=20;
                    }
                }
            } else {
                if (ch<125) {
                    if (ch<124) {
                        gsm7=40;
                    } else {
                        gsm7=64;
                    }
                } else {
                    if (ch<126) {
                        gsm7=41;
                    } else {
                        gsm7=61;
                    }
                }
            }
            res[wpos] = (char)(gsm7);
            wpos = wpos + 1;
        }
        i = i + 1;
    }
    return res;
}

int YMessageBox::checkNewMessages(void)
{
    string bitmapStr;
    string newBitmap;
    int slot = 0;
    int nslots = 0;
    int pduIdx = 0;
    int idx = 0;
    int bitVal = 0;
    int i = 0;
    int nsig = 0;
    int cnt = 0;
    string sig;
    bool isnew = 0;
    vector<YSms> newArr;
    vector<YSms> newMsg;
    vector<YSms> newAgg;
    vector<string> signatures;
    YSms sms;

    bitmapStr = this->get_slotsBitmap();
    if (bitmapStr == _prevBitmapStr) {
        return YAPI_SUCCESS;
    }
    _prevBitmapStr = bitmapStr;
    newBitmap = YAPI::_hexStr2Bin(bitmapStr);
    nslots = 8*(int)(newBitmap).size();
    newArr.clear();
    newMsg.clear();
    signatures.clear();
    nsig = 0;
    // copy known messages
    pduIdx = 0;
    while (pduIdx < (int)_pdus.size()) {
        sms = _pdus[pduIdx];
        slot = sms.get_slot();
        idx = (slot >> 3);
        if (idx < (int)(newBitmap).size()) {
            bitVal = (1 << (slot & 7));
            if ((((u8)newBitmap[idx]) & bitVal) != 0) {
                newBitmap[idx] = (char)((((u8)newBitmap[idx]) ^ bitVal));
                sms.set_new(false);
                newArr.push_back(sms);
                if (sms.get_concatCount() == 0) {
                    newMsg.push_back(sms);
                } else {
                    sig = sms.get_concatSignature();
                    i = 0;
                    while ((i < nsig) && ((int)(sig).length() > 0)) {
                        if (signatures[i] == sig) {
                            sig = "";
                        }
                        i = i + 1;
                    }
                    if ((int)(sig).length() > 0) {
                        signatures.push_back(sig);
                        nsig = nsig + 1;
                    }
                }
            }
        }
        pduIdx = pduIdx + 1;
    }
    // receive new messages
    slot = 0;
    while (slot < nslots) {
        idx = (slot >> 3);
        bitVal = (1 << (slot & 7));
        if ((((u8)newBitmap[idx]) & bitVal) != 0) {
            sms = this->fetchPdu(slot);
            sms.set_new(true);
            newArr.push_back(sms);
            if (sms.get_concatCount() == 0) {
                newMsg.push_back(sms);
            } else {
                sig = sms.get_concatSignature();
                i = 0;
                while ((i < nsig) && ((int)(sig).length() > 0)) {
                    if (signatures[i] == sig) {
                        sig = "";
                    }
                    i = i + 1;
                }
                if ((int)(sig).length() > 0) {
                    signatures.push_back(sig);
                    nsig = nsig + 1;
                }
            }
        }
        slot = slot + 1;
    }
    _pdus = newArr;
    // append complete concatenated messages
    newAgg.clear();
    i = 0;
    while (i < nsig) {
        sig = signatures[i];
        cnt = 0;
        pduIdx = 0;
        isnew = true;
        while (pduIdx < (int)_pdus.size()) {
            sms = _pdus[pduIdx];
            if (sms.get_concatCount() > 0) {
                if (sms.get_concatSignature() == sig) {
                    if (cnt == 0) {
                        cnt = sms.get_concatCount();
                        newAgg.clear();
                    }
                    isnew = sms.isNew();
                    newAgg.push_back(sms);
                }
            }
            pduIdx = pduIdx + 1;
        }
        if ((cnt > 0) && ((int)newAgg.size() == cnt)) {
            sms = YSms(this);
            sms.set_parts(newAgg);
            sms.set_new(isnew);
            newMsg.push_back(sms);
        }
        i = i + 1;
    }
    _messages = newMsg;
    return YAPI_SUCCESS;
}

vector<YSms> YMessageBox::get_pdus(void)
{
    this->checkNewMessages();
    return _pdus;
}

/**
 * Clear the SMS units counters.
 *
 * @return YAPI::SUCCESS when the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YMessageBox::clearPduCounters(void)
{
    int retcode = 0;

    retcode = this->set_pduReceived(0);
    if (retcode != YAPI_SUCCESS) {
        return retcode;
    }
    retcode = this->set_pduSent(0);
    return retcode;
}

/**
 * Sends a regular text SMS, with standard parameters. This function can send messages
 * of more than 160 characters, using SMS concatenation. ISO-latin accented characters
 * are supported. For sending messages with special unicode characters such as asian
 * characters and emoticons, use newMessage to create a new message and define
 * the content of using methods addText and addUnicodeData.
 *
 * @param recipient : a text string with the recipient phone number, either as a
 *         national number, or in international format starting with a plus sign
 * @param message : the text to be sent in the message
 *
 * @return YAPI::SUCCESS when the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YMessageBox::sendTextMessage(string recipient,string message)
{
    YSms sms;

    sms = YSms(this);
    sms.set_recipient(recipient);
    sms.addText(message);
    return sms.send();
}

/**
 * Sends a Flash SMS (class 0 message). Flash messages are displayed on the handset
 * immediately and are usually not saved on the SIM card. This function can send messages
 * of more than 160 characters, using SMS concatenation. ISO-latin accented characters
 * are supported. For sending messages with special unicode characters such as asian
 * characters and emoticons, use newMessage to create a new message and define
 * the content of using methods addText et addUnicodeData.
 *
 * @param recipient : a text string with the recipient phone number, either as a
 *         national number, or in international format starting with a plus sign
 * @param message : the text to be sent in the message
 *
 * @return YAPI::SUCCESS when the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
int YMessageBox::sendFlashMessage(string recipient,string message)
{
    YSms sms;

    sms = YSms(this);
    sms.set_recipient(recipient);
    sms.set_msgClass(0);
    sms.addText(message);
    return sms.send();
}

/**
 * Creates a new empty SMS message, to be configured and sent later on.
 *
 * @param recipient : a text string with the recipient phone number, either as a
 *         national number, or in international format starting with a plus sign
 *
 * @return YAPI::SUCCESS when the call succeeds.
 *
 * On failure, throws an exception or returns a negative error code.
 */
YSms YMessageBox::newMessage(string recipient)
{
    YSms sms;
    sms = YSms(this);
    sms.set_recipient(recipient);
    return sms;
}

/**
 * Returns the list of messages received and not deleted. This function
 * will automatically decode concatenated SMS.
 *
 * @return an YSms object list.
 *
 * On failure, throws an exception or returns an empty list.
 */
vector<YSms> YMessageBox::get_messages(void)
{
    this->checkNewMessages();
    return _messages;
}

/**
 * Registers a callback function to be called each time that a new SMS is received.
 * The callback is invoked only during the execution of ySleep or yHandleEvents.
 * This provides control over the time when the callback is triggered.
 * For good responsiveness, remember to call one of these two functions periodically.
 * To unregister a callback, pass a NULL pointer as argument.
 *
 * @param callback : the callback function to call, or a NULL pointer.
 *         The callback function should take four arguments:
 *         the YMessageBox object that emitted the event, and
 *         the YSms object containing the received message.
 *         On failure, throws an exception or returns a negative error code.
 */
int YMessageBox::registerSmsCallback(YSmsCallback callback)
{
    _smsCallback = (YSmsCallback) NULL;
    if (callback != NULL) {
        this->registerValueCallback(yInternalEventCallback);
    } else {
        this->registerValueCallback((YMessageBoxValueCallback) NULL);
    }
    _smsCallback = callback;
    return 0;
}

int YMessageBox::_internalEventHandler(string cbVal)
{
    int arrLen = 0;
    int arrPos = 0;
    vector<YSms> messages;
    YSms sms;

    messages = this->get_messages();
    // invoke callback for all new messages
    arrLen = (int)messages.size();
    arrPos = 0;
    while (arrPos < arrLen) {
        sms = messages[arrPos];
        if (sms.isNew()) {
            if (_smsCallback != NULL) {
                _smsCallback(this, sms);
            }
        }
        arrPos = arrPos + 1;
    }
    return YAPI_SUCCESS;
}

YMessageBox *YMessageBox::nextMessageBox(void)
{
    string  hwid;

    if(YISERR(_nextFunction(hwid)) || hwid=="") {
        return NULL;
    }
    return YMessageBox::FindMessageBox(hwid);
}

YMessageBox *YMessageBox::FirstMessageBox(void)
{
    vector<YFUN_DESCR>   v_fundescr;
    YDEV_DESCR             ydevice;
    string              serial, funcId, funcName, funcVal, errmsg;

    if(YISERR(YapiWrapper::getFunctionsByClass("MessageBox", 0, v_fundescr, sizeof(YFUN_DESCR), errmsg)) ||
       v_fundescr.size() == 0 ||
       YISERR(YapiWrapper::getFunctionInfo(v_fundescr[0], ydevice, serial, funcId, funcName, funcVal, errmsg))) {
        return NULL;
    }
    return YMessageBox::FindMessageBox(serial+"."+funcId);
}

//--- (end of generated code: YMessageBox implementation)

//--- (generated code: YMessageBox functions)
//--- (end of generated code: YMessageBox functions)
