<commit_before>#include "openssl/x509.h"
#include "openssl/ssl.h"
#include "openssl/bio.h"
#include "openssl/err.h"

#include "openssl/x509_vfy.h"

//#include "openssl/safestack.h"

#include <windows.h>
#include <wincrypt.h>

DWORD WINAPI CertGetPublicKeyLength(
  DWORD dwCertEncodingType,
  PCERT_PUBLIC_KEY_INFO pPublicKey
);

#include "sslhelper.h"
#include <stdio.h>
#include <iostream>

#include <sstream>

using namespace std;

static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx);

typedef struct {
   int verbose_mode;
   int verify_depth;
   int always_continue;
   SSLHelper * helper;
 } mydata_t;
 int mydata_index;

SSLHelper::SSLHelper()
{
    log( "starting SSL helper" );

    ctx = loadCertificates();
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
    if(!ctx)
    {
        log( string("loadCertificates: ") + string(ERR_reason_error_string(ERR_get_error())) );
        return;
    }

    ssl = SSL_new(ctx);
    if(!ssl)
    {
        log( string("SSL_new: ") + string(ERR_reason_error_string(ERR_get_error())) );

        return;
    }

    log( "creating BIO" );
    bio = BIO_new_ssl_connect(ctx);
    if(bio == NULL)
    {
        log( "failure to create BIO" );
        return;
    }
}

SSLHelper::~SSLHelper()
{
    log( "closing ssl helper" );
    SSL_CTX_free(ctx);
    BIO_free_all(bio);
}

void SSLHelper::testConnection(string host, string port)
{
    log( string("ssl to host=") + host + " and port=" + port );

    BIO_set_conn_hostname(bio, (char * )host.c_str());
    BIO_set_conn_port(bio, (char *)port.c_str());

    BIO_get_ssl(bio, & ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    SSL_CTX_set_verify_depth(ctx, 10);

    mydata_t mydata;
    mydata_index = SSL_get_ex_new_index(0, (void *)"mydata index", NULL, NULL, NULL);
    mydata.verify_depth = 10;
    mydata.verbose_mode = 1;
    mydata.always_continue = 1;
    mydata.helper = this;
    SSL_set_ex_data(ssl, mydata_index, &mydata);

    log( "trying to connect" );

    if(BIO_do_connect(bio) <= 0)
    {
        /* Handle failed connection */
        log( string("failure to connect: " ) + string(ERR_reason_error_string(ERR_get_error())) );
        return;
    }
    log( "connected" );

    SSL_accept(ssl);
    if(SSL_get_verify_result(ssl) != X509_V_OK)
    {
        /* Handle the failed verification */
        std::ostringstream oss;
        oss << "unverified connection: " << SSL_get_verify_result(ssl) ;
        log( oss.str() );
    }
    else
       log( "verified connection" );

    log( "\n==================================\n" );

    //log( string("verify depth: ") + SSL_CTX_get_verify_depth(ctx) );
    //log( string("verify  mode: ") + SSL_CTX_get_verify_mode(ctx) );

}

SSL_CTX * SSLHelper::loadCertificates()
{
    SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());

    //int err = 0;
    X509_STORE *store = SSL_CTX_get_cert_store(ctx);
    HCERTSTORE hCertStore = CertOpenSystemStore(0, L"ROOT");

    if(!hCertStore)
    {
        log( "couldn't open the certificate store" );
        return NULL;
    }

    PCCERT_CONTEXT pCertContext = CertEnumCertificatesInStore(hCertStore, NULL);
    while ( pCertContext )
    {
        X509 *cert = d2i_X509(NULL, (const unsigned char **)&pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
        if (X509_STORE_add_cert(store, (X509 *)cert) != 1)
        {
            unsigned long err2;
            string abcd("SSL Error: ");
            err2 = ERR_get_error();
            /* continue if error == certificate already in store */
            if(ERR_GET_REASON(err2) != 101)
            {
                while(err2 != 0) {
                    ostringstream res;
                    res << err2;
                    res << " number=";
                    res << ERR_GET_LIB(err2);
                    res << ", function=";
                    res << ERR_GET_FUNC(err2);
                    res << ", reason code=";
                    res << ERR_GET_REASON(err2);
                    res << "\n";
                    abcd += res.str();
                    err2 = ERR_get_error();
                }
                log( abcd.c_str() );
                return NULL;
            }
        }

        pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext);
    }

    log( "root certificates loaded" );

    return ctx;
}

void SSLHelper::log(string text)
{
    logger << text << endl;
    emit(logging());
}

void SSLHelper::log(ostream text)
{
    logger << text << endl;
    emit(logging());
}

void SSLHelper::showCAs()
{
    HCERTSTORE         hStoreHandle = NULL;
    PCCERT_CONTEXT     pCertContext = NULL;
    char                pszNameString[256];

    if (hStoreHandle = CertOpenSystemStore(
         NULL,
         L"ROOT"))
        {
             //log("The store has been opened. \n");
        }
        else
        {
             log("The store was not opened.\n");
        }

    while(pCertContext = CertEnumCertificatesInStore(
          hStoreHandle,
          pCertContext))
    {
        //PCERT_INFO certinfo = pCertContext->pCertInfo;
        if(CertGetNameStringA(
           pCertContext,
           CERT_NAME_SIMPLE_DISPLAY_TYPE,
           0,
           NULL,
           pszNameString,
           256))
        {
            std::ostringstream oss;
            //oss << "Certificate retrieved: " << pszNameString;
            //log( oss.str() );
        }
        string name = pszNameString;
        std::ostringstream oss;
        if(CertGetNameStringA(
           pCertContext,
           CERT_NAME_SIMPLE_DISPLAY_TYPE,
           0x1, //=CERT_NAME_ISSUER_FLAG,
           NULL,
           pszNameString,
           256))
        {
            oss << "Issued by:\t\t" << pszNameString << endl;
            //log( oss.str() );
        }
        //string issuer = "Issued by: ";
        //issuer += pszNameString;
        /*int keylength = CertGetPublicKeyLength(pCertContext->dwCertEncodingType, &pCertContext->pCertInfo->SubjectPublicKeyInfo);
        std::ostringstream oss;
        oss << "key length: " << keylength << endl;*/

        //string result = pCertContext->pCertInfo->SignatureAlgorithm.pszObjId;
        oss << "Signature algorithm:\t" << CertOIDToAlgId( pCertContext->pCertInfo->SignatureAlgorithm.pszObjId ) << endl;

        SYSTEMTIME stUTC, stLocal;
        FileTimeToSystemTime(&pCertContext->pCertInfo->NotBefore, &stUTC);
        SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

        oss << "Not before:\t\t" << stLocal.wDay << "/" << stLocal.wMonth << "/" << stLocal.wYear;
        oss << "  " << stLocal.wHour << ":" << stLocal.wMinute << endl;

        //SYSTEMTIME stUTC, stLocal;
        FileTimeToSystemTime(&pCertContext->pCertInfo->NotAfter, &stUTC);
        SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

        oss << "Not after:\t\t" << stLocal.wDay << "/" << stLocal.wMonth << "/" << stLocal.wYear;
        oss << "  " << stLocal.wHour << ":" << stLocal.wMinute << endl;

        emit(addCA(name, oss.str()));
    }

    if (!CertCloseStore(
             hStoreHandle,
             0))
    {
        log("Failed CertCloseStore\n");
    }
}

void SSLHelper::dumpCerts()
{
    HCERTSTORE         hStoreHandle = NULL;
    PCCERT_CONTEXT     pCertContext = NULL;
    char                pszNameString[256];

    if (hStoreHandle = CertOpenSystemStore(
         NULL,
         L"ROOT"))
        {
             //log("The store has been opened. \n");
        }
        else
        {
             log("The store was not opened.\n");
             return;
        }

    while(pCertContext = CertEnumCertificatesInStore(
          hStoreHandle,
          pCertContext))
    {
        if(CertGetNameStringA(
           pCertContext,
           CERT_NAME_SIMPLE_DISPLAY_TYPE,
           0,
           NULL,
           pszNameString,
           256))
        {
            std::ostringstream oss;
        }
        string name = pszNameString;

        exportPFX(pCertContext, name+".der");
    }

    if (!CertCloseStore(
             hStoreHandle,
             0))
    {
        log("Failed CertCloseStore\n");
    }

    wchar_t path[MAX_PATH];
    GetCurrentDirectory(MAX_PATH,path);

    ShellExecute(NULL, L"explore", path, NULL, NULL, SW_SHOWNORMAL);
}

void SSLHelper::exportPFX( PCCERT_CONTEXT pCertContext,
     string name )
 {
     int rc = NO_ERROR;

     HANDLE hFile = CreateFileA(name.c_str(),
         GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     if (hFile != INVALID_HANDLE_VALUE) {
         DWORD writtenBytes = 0;
         if (WriteFile(hFile, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, &writtenBytes, NULL)) {
             cout << "3 Written to a pfx file\n" << endl;
             //OK
         } else {
             rc = GetLastError();
         }
         CloseHandle(hFile);
     } else {
         cout <<"4 Failed to open a file " << name << endl;
         rc = GetLastError();
     }
 }

static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
   char    buf[256];
   char    issuer[256];
   X509   *err_cert;
   int     err, depth;
   SSL    *ssl;
   mydata_t *mydata;

   err_cert = X509_STORE_CTX_get_current_cert(ctx);
   err = X509_STORE_CTX_get_error(ctx);
   depth = X509_STORE_CTX_get_error_depth(ctx);

   /*
    * Retrieve the pointer to the SSL of the connection currently treated
    * and the application specific data stored into the SSL object.
    */
   ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
   mydata = (mydata_t *)SSL_get_ex_data(ssl, mydata_index);

   X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
   X509_NAME_oneline(X509_get_issuer_name(err_cert), issuer, 256);

   /*
    * Catch a too long certificate chain. The depth limit set using
    * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
    * that whenever the "depth>verify_depth" condition is met, we
    * have violated the limit and want to log this error condition.
    * We must do it here, because the CHAIN_TOO_LONG error would not
    * be found explicitly; only errors introduced by cutting off the
    * additional certificates would be logged.
    */
   if (depth > mydata->verify_depth) {
       preverify_ok = 0;
       err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
       X509_STORE_CTX_set_error(ctx, err);
   }
   if (!preverify_ok) {
       //printf("verify error:num=%d:%s:depth=%d:%s\n", err,
       //         X509_verify_cert_error_string(err), depth, buf);
       std::ostringstream oss;
       oss << "verify error:num=" << err << ":" << X509_verify_cert_error_string(err) << endl;
       oss << "depth=" << depth << ":" << endl;
       oss << "\t-> subject:   "<< buf << endl;
       oss << "\t-> issued by: " << issuer << endl;
       mydata->helper->log( oss.str() );
   }
   else if (mydata->verbose_mode)
   {
       std::ostringstream oss;
       oss << "depth=" << depth << ":" << endl;
       oss << "\t-> subject:   "<< buf << endl;
       oss << "\t-> issued by: " << issuer << endl;
       mydata->helper->log( oss.str() );
       //mydata->helper->log( string("depth=") + string(depth) + string(":") + string(buf) );
   }

   /*
    * At this point, err contains the last verification error. We can use
    * it for something special
    */
   if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
   {
     X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
     //printf("issuer= %s\n", buf);
     std::ostringstream oss;
     oss << "issuer = " << buf;
     mydata->helper->log( oss.str() );
     //mydata->helper->log( string("issuer = ") + string(buf) );
   }

   if (mydata->always_continue)
     return 1;
   else
     return preverify_ok;
}
<commit_msg>clean up the logs<commit_after>#include "openssl/x509.h"
#include "openssl/ssl.h"
#include "openssl/bio.h"
#include "openssl/err.h"

#include "openssl/x509_vfy.h"

//#include "openssl/safestack.h"

#include <windows.h>
#include <wincrypt.h>

DWORD WINAPI CertGetPublicKeyLength(
  DWORD dwCertEncodingType,
  PCERT_PUBLIC_KEY_INFO pPublicKey
);

#include "sslhelper.h"
#include <stdio.h>
#include <iostream>

#include <sstream>

using namespace std;

static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx);

typedef struct {
   int verbose_mode;
   int verify_depth;
   int always_continue;
   SSLHelper * helper;
 } mydata_t;
 int mydata_index;

SSLHelper::SSLHelper()
{
    ctx = loadCertificates();
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
    if(!ctx)
    {
        log( string("loadCertificates: ") + string(ERR_reason_error_string(ERR_get_error())) );
        return;
    }

    ssl = SSL_new(ctx);
    if(!ssl)
    {
        log( string("SSL_new: ") + string(ERR_reason_error_string(ERR_get_error())) );

        return;
    }

    bio = BIO_new_ssl_connect(ctx);
    if(bio == NULL)
    {
        log( "failure to create BIO" );
        return;
    }
}

SSLHelper::~SSLHelper()
{
    SSL_CTX_free(ctx);
    BIO_free_all(bio);
}

void SSLHelper::testConnection(string host, string port)
{
    log( string("Connecting to ") + host + " on port " + port );

    BIO_set_conn_hostname(bio, (char * )host.c_str());
    BIO_set_conn_port(bio, (char *)port.c_str());

    BIO_get_ssl(bio, & ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    SSL_CTX_set_verify_depth(ctx, 10);

    mydata_t mydata;
    mydata_index = SSL_get_ex_new_index(0, (void *)"mydata index", NULL, NULL, NULL);
    mydata.verify_depth = 10;
    mydata.verbose_mode = 1;
    mydata.always_continue = 1;
    mydata.helper = this;
    SSL_set_ex_data(ssl, mydata_index, &mydata);

    log( "trying to connect..." );

    if(BIO_do_connect(bio) <= 0)
    {
        /* Handle failed connection */
        log( string("failure to connect: " ) + string(ERR_reason_error_string(ERR_get_error())) );
        return;
    }
    log( "connected" );

    SSL_accept(ssl);
    if(SSL_get_verify_result(ssl) != X509_V_OK)
    {
        /* Handle the failed verification */
        std::ostringstream oss;
        oss << "unverified connection: " << SSL_get_verify_result(ssl) ;
        log( oss.str() );
    }
    else
       log( "connection verified" );

    log( "\n==================================\n" );
}

SSL_CTX * SSLHelper::loadCertificates()
{
    SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());

    //int err = 0;
    X509_STORE *store = SSL_CTX_get_cert_store(ctx);
    HCERTSTORE hCertStore = CertOpenSystemStore(0, L"ROOT");

    if(!hCertStore)
    {
        log( "couldn't open the certificate store" );
        return NULL;
    }

    PCCERT_CONTEXT pCertContext = CertEnumCertificatesInStore(hCertStore, NULL);
    while ( pCertContext )
    {
        X509 *cert = d2i_X509(NULL, (const unsigned char **)&pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
        if (X509_STORE_add_cert(store, (X509 *)cert) != 1)
        {
            unsigned long err2;
            string abcd("SSL Error: ");
            err2 = ERR_get_error();
            /* continue if error == certificate already in store */
            if(ERR_GET_REASON(err2) != 101)
            {
                while(err2 != 0) {
                    ostringstream res;
                    res << err2;
                    res << " number=";
                    res << ERR_GET_LIB(err2);
                    res << ", function=";
                    res << ERR_GET_FUNC(err2);
                    res << ", reason code=";
                    res << ERR_GET_REASON(err2);
                    res << "\n";
                    abcd += res.str();
                    err2 = ERR_get_error();
                }
                log( abcd.c_str() );
                return NULL;
            }
        }

        pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext);
    }
    return ctx;
}

void SSLHelper::log(string text)
{
    logger << text << endl;
    emit(logging());
}

void SSLHelper::log(ostream text)
{
    logger << text << endl;
    emit(logging());
}

void SSLHelper::showCAs()
{
    HCERTSTORE         hStoreHandle = NULL;
    PCCERT_CONTEXT     pCertContext = NULL;
    char                pszNameString[256];

    if (hStoreHandle = CertOpenSystemStore(
         NULL,
         L"ROOT"))
        {
             //log("The store has been opened. \n");
        }
        else
        {
             log("The store was not opened.\n");
        }

    while(pCertContext = CertEnumCertificatesInStore(
          hStoreHandle,
          pCertContext))
    {
        //PCERT_INFO certinfo = pCertContext->pCertInfo;
        if(CertGetNameStringA(
           pCertContext,
           CERT_NAME_SIMPLE_DISPLAY_TYPE,
           0,
           NULL,
           pszNameString,
           256))
        {
            std::ostringstream oss;
            //oss << "Certificate retrieved: " << pszNameString;
            //log( oss.str() );
        }
        string name = pszNameString;
        std::ostringstream oss;
        if(CertGetNameStringA(
           pCertContext,
           CERT_NAME_SIMPLE_DISPLAY_TYPE,
           0x1, //=CERT_NAME_ISSUER_FLAG,
           NULL,
           pszNameString,
           256))
        {
            oss << "Issued by:\t\t" << pszNameString << endl;
            //log( oss.str() );
        }
        //string issuer = "Issued by: ";
        //issuer += pszNameString;
        /*int keylength = CertGetPublicKeyLength(pCertContext->dwCertEncodingType, &pCertContext->pCertInfo->SubjectPublicKeyInfo);
        std::ostringstream oss;
        oss << "key length: " << keylength << endl;*/

        //string result = pCertContext->pCertInfo->SignatureAlgorithm.pszObjId;
        oss << "Signature algorithm:\t" << CertOIDToAlgId( pCertContext->pCertInfo->SignatureAlgorithm.pszObjId ) << endl;

        SYSTEMTIME stUTC, stLocal;
        FileTimeToSystemTime(&pCertContext->pCertInfo->NotBefore, &stUTC);
        SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

        oss << "Not before:\t\t" << stLocal.wDay << "/" << stLocal.wMonth << "/" << stLocal.wYear;
        oss << "  " << stLocal.wHour << ":" << stLocal.wMinute << endl;

        //SYSTEMTIME stUTC, stLocal;
        FileTimeToSystemTime(&pCertContext->pCertInfo->NotAfter, &stUTC);
        SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

        oss << "Not after:\t\t" << stLocal.wDay << "/" << stLocal.wMonth << "/" << stLocal.wYear;
        oss << "  " << stLocal.wHour << ":" << stLocal.wMinute << endl;

        emit(addCA(name, oss.str()));
    }

    if (!CertCloseStore(
             hStoreHandle,
             0))
    {
        log("Failed CertCloseStore\n");
    }
}

void SSLHelper::dumpCerts()
{
    HCERTSTORE         hStoreHandle = NULL;
    PCCERT_CONTEXT     pCertContext = NULL;
    char                pszNameString[256];

    if (hStoreHandle = CertOpenSystemStore(
         NULL,
         L"ROOT"))
        {
             //log("The store has been opened. \n");
        }
        else
        {
             log("The store was not opened.\n");
             return;
        }

    while(pCertContext = CertEnumCertificatesInStore(
          hStoreHandle,
          pCertContext))
    {
        if(CertGetNameStringA(
           pCertContext,
           CERT_NAME_SIMPLE_DISPLAY_TYPE,
           0,
           NULL,
           pszNameString,
           256))
        {
            std::ostringstream oss;
        }
        string name = pszNameString;

        exportPFX(pCertContext, name+".der");
    }

    if (!CertCloseStore(
             hStoreHandle,
             0))
    {
        log("Failed CertCloseStore\n");
    }

    wchar_t path[MAX_PATH];
    GetCurrentDirectory(MAX_PATH,path);

    ShellExecute(NULL, L"explore", path, NULL, NULL, SW_SHOWNORMAL);
}

void SSLHelper::exportPFX( PCCERT_CONTEXT pCertContext,
     string name )
 {
     int rc = NO_ERROR;

     HANDLE hFile = CreateFileA(name.c_str(),
         GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     if (hFile != INVALID_HANDLE_VALUE) {
         DWORD writtenBytes = 0;
         if (WriteFile(hFile, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, &writtenBytes, NULL)) {
             cout << "3 Written to a pfx file\n" << endl;
             //OK
         } else {
             rc = GetLastError();
         }
         CloseHandle(hFile);
     } else {
         cout <<"4 Failed to open a file " << name << endl;
         rc = GetLastError();
     }
 }

static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
   char    buf[256];
   char    issuer[256];
   X509   *err_cert;
   int     err, depth;
   SSL    *ssl;
   mydata_t *mydata;

   err_cert = X509_STORE_CTX_get_current_cert(ctx);
   err = X509_STORE_CTX_get_error(ctx);
   depth = X509_STORE_CTX_get_error_depth(ctx);

   /*
    * Retrieve the pointer to the SSL of the connection currently treated
    * and the application specific data stored into the SSL object.
    */
   ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
   mydata = (mydata_t *)SSL_get_ex_data(ssl, mydata_index);

   X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
   X509_NAME_oneline(X509_get_issuer_name(err_cert), issuer, 256);

   /*
    * Catch a too long certificate chain. The depth limit set using
    * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
    * that whenever the "depth>verify_depth" condition is met, we
    * have violated the limit and want to log this error condition.
    * We must do it here, because the CHAIN_TOO_LONG error would not
    * be found explicitly; only errors introduced by cutting off the
    * additional certificates would be logged.
    */
   if (depth > mydata->verify_depth) {
       preverify_ok = 0;
       err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
       X509_STORE_CTX_set_error(ctx, err);
   }
   if (!preverify_ok) {
       //printf("verify error:num=%d:%s:depth=%d:%s\n", err,
       //         X509_verify_cert_error_string(err), depth, buf);
       std::ostringstream oss;
       oss << "verify error:num=" << err << ":" << X509_verify_cert_error_string(err) << endl;
       oss << "depth=" << depth << ":" << endl;
       oss << "\t-> subject:   "<< buf << endl;
       oss << "\t-> issued by: " << issuer << endl;
       mydata->helper->log( oss.str() );
   }
   else if (mydata->verbose_mode)
   {
       std::ostringstream oss;
       oss << "depth=" << depth << ":" << endl;
       oss << "\t-> subject:   "<< buf << endl;
       oss << "\t-> issued by: " << issuer << endl;
       mydata->helper->log( oss.str() );
       //mydata->helper->log( string("depth=") + string(depth) + string(":") + string(buf) );
   }

   /*
    * At this point, err contains the last verification error. We can use
    * it for something special
    */
   if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
   {
     X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
     //printf("issuer= %s\n", buf);
     std::ostringstream oss;
     oss << "issuer = " << buf;
     mydata->helper->log( oss.str() );
     //mydata->helper->log( string("issuer = ") + string(buf) );
   }

   if (mydata->always_continue)
     return 1;
   else
     return preverify_ok;
}
<|endoftext|>


<commit_before>/**
 * @author ChalkPE <chalkpe@gmail.com>
 * @since 2016-04-11
 */

#include <stdio.h>
int main(){
    printf("%d %d \n", 3 & 1, 3 | 1);
    printf("%d \n", 3 ^ 1);
    printf("%d %d \n", 3 << 1, 3 >> 1);
    printf("%d \n", 1 << 32 - 1);
    return 0;

    /*
     *   0000 0010 = +2
     *   1000 0010
     *   0000 0011 = +3
     *  10000 0001 = +1
     *
     *   1111 1110 = -2
     * 1 0000 0000 =  0
     */
}

//END OF FILE<commit_msg>Small changes<commit_after>/**
 * @author ChalkPE <chalkpe@gmail.com>
 * @since 2016-04-11
 */

#include <stdio.h>
int main(){
    printf("%d %d \n", 3 & 1, 3 | 1);
    printf("%d \n", 3 ^ 1);
    printf("%d %d \n", 3 << 1, 3 >> 1);
    printf("%d \n", 1 << 32 - 1);
    return 0;

    /*
     *   0000 0010 = +2
     *   1000 0010
     *   0000 0011 = +3
     * 1 0000 0001 = +1
     *
     *   1111 1110 = -2
     * 1 0000 0000 =  0
     */
}

//END OF FILE<|endoftext|>


<commit_before>#ifndef _SOT_CORE_CAUSAL_FILTER_H_
#define _SOT_CORE_CAUSAL_FILTER_H_
/*
 * Copyright 2017-, Rohan Budhirja, LAAS-CNRS
 *
 * This file is part of sot-torque-control.
 * sot-torque-control is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * sot-torque-control 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 Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with sot-torque-control.  If not, see <http://www.gnu.org/licenses/>.
 */

/* --------------------------------------------------------------------- */
/* --- INCLUDE --------------------------------------------------------- */
/* --------------------------------------------------------------------- */
#include <Eigen/Core>

/** \addtogroup Filters
    \section subsec_causalfilter CausalFilter
    Filter data with an IIR or FIR filter.

    Filter a data sequence, \f$x\f$, using a digital filter.
    The filter is a direct form II transposed implementation
    of the standard difference equation.
    This means that the filter implements:

    \f$ a[0]*y[N] = b[0]*x[N] + b[1]*x[N-1] + ... + b[m-1]*x[N-(m-1)]
    - a[1]*y[N-1] - ... - a[n-1]*y[N-(n-1)] \f$

    where \f$m\f$ is the degree of the numerator,
    \f$n\f$ is the degree of the denominator,
    and \f$N\f$ is the sample number

 */
namespace dynamicgraph {
  namespace sot {

    class CausalFilter
    {
    public:
      EIGEN_MAKE_ALIGNED_OPERATOR_NEW

      /** --- CONSTRUCTOR ----
	  \param[in] timestep
	  \param[in] xSize
	  \param[in] filter_numerator
	  \param[in] filter_denominator

	  xSize is
      */
      CausalFilter(const double &timestep,
		   const int& xSize,
		   const Eigen::VectorXd& filter_numerator,
		   const Eigen::VectorXd& filter_denominator);

      void get_x_dx_ddx(const Eigen::VectorXd& base_x,
			Eigen::VectorXd& x_output_dx_ddx);

      void switch_filter(const Eigen::VectorXd& filter_numerator,
			 const Eigen::VectorXd& filter_denominator);

    private:
      /// sampling timestep of the input signal
      double m_dt;
      /// Size
      int m_x_size;
      /// Size of the numerator \f$m\f$
      Eigen::Index m_filter_order_m;
      /// Size of the denominator \f$n\f$
      Eigen::Index m_filter_order_n;

      /// Coefficients of the numerator \f$b\f$
      Eigen::VectorXd m_filter_numerator;
      /// Coefficients of the denominator \f$a\f$
      Eigen::VectorXd m_filter_denominator;
      bool m_first_sample;
      ///
      int m_pt_numerator;
      int m_pt_denominator;
      Eigen::MatrixXd m_input_buffer;
      Eigen::MatrixXd m_output_buffer;
    }; // class CausalFilter
  } /// core
} /// sot
#endif /* _SOT_CORE_CAUSAL_FILTER_H_ */
<commit_msg>[filter] Causal-filter fix Eigen::Index to Eigen::VectorXd::Index<commit_after>#ifndef _SOT_CORE_CAUSAL_FILTER_H_
#define _SOT_CORE_CAUSAL_FILTER_H_
/*
 * Copyright 2017-, Rohan Budhirja, LAAS-CNRS
 *
 * This file is part of sot-torque-control.
 * sot-torque-control is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * sot-torque-control 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 Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with sot-torque-control.  If not, see <http://www.gnu.org/licenses/>.
 */

/* --------------------------------------------------------------------- */
/* --- INCLUDE --------------------------------------------------------- */
/* --------------------------------------------------------------------- */
#include <Eigen/Core>

/** \addtogroup Filters
    \section subsec_causalfilter CausalFilter
    Filter data with an IIR or FIR filter.

    Filter a data sequence, \f$x\f$, using a digital filter.
    The filter is a direct form II transposed implementation
    of the standard difference equation.
    This means that the filter implements:

    \f$ a[0]*y[N] = b[0]*x[N] + b[1]*x[N-1] + ... + b[m-1]*x[N-(m-1)]
    - a[1]*y[N-1] - ... - a[n-1]*y[N-(n-1)] \f$

    where \f$m\f$ is the degree of the numerator,
    \f$n\f$ is the degree of the denominator,
    and \f$N\f$ is the sample number

 */
namespace dynamicgraph {
  namespace sot {

    class CausalFilter
    {
    public:
      EIGEN_MAKE_ALIGNED_OPERATOR_NEW

      /** --- CONSTRUCTOR ----
	  \param[in] timestep
	  \param[in] xSize
	  \param[in] filter_numerator
	  \param[in] filter_denominator

	  xSize is
      */
      CausalFilter(const double &timestep,
		   const int& xSize,
		   const Eigen::VectorXd& filter_numerator,
		   const Eigen::VectorXd& filter_denominator);

      void get_x_dx_ddx(const Eigen::VectorXd& base_x,
			Eigen::VectorXd& x_output_dx_ddx);

      void switch_filter(const Eigen::VectorXd& filter_numerator,
			 const Eigen::VectorXd& filter_denominator);

    private:
      /// sampling timestep of the input signal
      double m_dt;
      /// Size
      int m_x_size;
      /// Size of the numerator \f$m\f$
      Eigen::VectorXd::Index m_filter_order_m;
      /// Size of the denominator \f$n\f$
      Eigen::VectorXd::Index m_filter_order_n;

      /// Coefficients of the numerator \f$b\f$
      Eigen::VectorXd m_filter_numerator;
      /// Coefficients of the denominator \f$a\f$
      Eigen::VectorXd m_filter_denominator;
      bool m_first_sample;
      ///
      int m_pt_numerator;
      int m_pt_denominator;
      Eigen::MatrixXd m_input_buffer;
      Eigen::MatrixXd m_output_buffer;
    }; // class CausalFilter
  } /// core
} /// sot
#endif /* _SOT_CORE_CAUSAL_FILTER_H_ */
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "topojson_datasource.hpp"
#include "topojson_featureset.hpp"

#include <fstream>
#include <algorithm>

// boost

#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>

// mapnik
#include <mapnik/unicode.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/json/topojson_grammar.hpp>
#include <mapnik/json/topojson_grammar_impl.hpp>
#include <mapnik/json/topojson_utils.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/make_unique.hpp>

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(topojson_datasource)

struct attr_value_converter : public mapnik::util::static_visitor<mapnik::eAttributeType>
{
    mapnik::eAttributeType operator() (mapnik::value_integer /*val*/) const
    {
        return mapnik::Integer;
    }

    mapnik::eAttributeType operator() (double /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (float /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (bool /*val*/) const
    {
        return mapnik::Boolean;
    }

    mapnik::eAttributeType operator() (std::string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_unicode_string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_null const& /*val*/) const
    {
        return mapnik::String;
    }
};

struct geometry_type_visitor : public mapnik::util::static_visitor<int>
{
    int operator() (mapnik::topojson::point const&) const
    {
        return static_cast<int>(mapnik::datasource::Point);
    }
    int operator() (mapnik::topojson::multi_point const&) const
    {
        return static_cast<int>(mapnik::datasource::Point);
    }
    int operator() (mapnik::topojson::linestring const&) const
    {
        return static_cast<int>(mapnik::datasource::LineString);
    }
    int operator() (mapnik::topojson::multi_linestring const&) const
    {
        return static_cast<int>(mapnik::datasource::LineString);
    }
    int operator() (mapnik::topojson::polygon const&) const
    {
        return static_cast<int>(mapnik::datasource::Polygon);
    }
    int operator() (mapnik::topojson::multi_polygon const&) const
    {
        return static_cast<int>(mapnik::datasource::Polygon);
    }
    int operator() (mapnik::topojson::invalid const&) const
    {
        return -1;
    }
};

struct collect_attributes_visitor : public mapnik::util::static_visitor<void>
{
    mapnik::layer_descriptor & desc_;
    collect_attributes_visitor(mapnik::layer_descriptor & desc):
      desc_(desc) {}

    void operator() (mapnik::topojson::invalid const& g) {}

    template <typename GeomType>
    void operator() (GeomType const& g)
    {
        if (g.props)
        {
            for (auto const& p : *g.props)
            {
                desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(p),
                                                                  mapnik::util::apply_visitor(attr_value_converter(),
                                                                                std::get<1>(p))));
            }
        }
    }
};

topojson_datasource::topojson_datasource(parameters const& params)
  : datasource(params),
    type_(datasource::Vector),
    desc_(topojson_datasource::name(),
          *params.get<std::string>("encoding","utf-8")),
    filename_(),
    inline_string_(),
    extent_(),
    tr_(new mapnik::transcoder(*params.get<std::string>("encoding","utf-8"))),
    tree_(nullptr)
{
    boost::optional<std::string> inline_string = params.get<std::string>("inline");
    if (inline_string)
    {
        inline_string_ = *inline_string;
    }
    else
    {
        boost::optional<std::string> file = params.get<std::string>("file");
        if (!file) throw mapnik::datasource_exception("TopoJSON Plugin: missing <file> parameter");

        boost::optional<std::string> base = params.get<std::string>("base");
        if (base)
            filename_ = *base + "/" + *file;
        else
            filename_ = *file;
    }
    if (!inline_string_.empty())
    {
        std::istringstream in(inline_string_);
        parse_topojson(in);
    }
    else
    {
#if defined (_WINDOWS)
        std::ifstream in(mapnik::utf8_to_utf16(filename_),std::ios_base::in | std::ios_base::binary);
#else
        std::ifstream in(filename_.c_str(),std::ios_base::in | std::ios_base::binary);
#endif
        if (!in.is_open())
        {
            throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'");
        }
        parse_topojson(in);
        in.close();
    }
}

template <typename T>
void topojson_datasource::parse_topojson(T & stream)
{
    using base_iterator_type = std::istreambuf_iterator<char>;
    boost::spirit::multi_pass<base_iterator_type> begin =
        boost::spirit::make_default_multi_pass(base_iterator_type(stream));

    boost::spirit::multi_pass<base_iterator_type> end =
        boost::spirit::make_default_multi_pass(base_iterator_type());

    static const mapnik::topojson::topojson_grammar<boost::spirit::multi_pass<base_iterator_type> > g;
    boost::spirit::standard_wide::space_type space;
    bool result = boost::spirit::qi::phrase_parse(begin, end, g, space, topo_);
    if (!result)
    {
        throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + filename_ + "'");
    }

    using values_container = std::vector< std::pair<box_type, std::size_t> >;
    values_container values;
    values.reserve(topo_.geometries.size());
    std::size_t geometry_index = 0;

    for (auto const& geom : topo_.geometries)
    {
        mapnik::box2d<double> box = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo_), geom);
        if (box.valid())
        {
            if (geometry_index == 0)
            {
                extent_ = box;
                collect_attributes_visitor assessor(desc_);
                mapnik::util::apply_visitor( std::ref(assessor), geom);
            }
            else
            {
                extent_.expand_to_include(box);
            }
        }
#if BOOST_VERSION >= 105600
        values.emplace_back(box_type(point_type(box.minx(),box.miny()),point_type(box.maxx(),box.maxy())), geometry_index);
#else
        values.emplace_back(box_type(point_type(box.minx(),box.miny()),point_type(box.maxx(),box.maxy())),geometry_index);
#endif
        ++geometry_index;
    }

#if BOOST_VERSION >= 105600
    // packing algorithm
    tree_ = std::make_unique<spatial_index_type>(values);
#else
    tree_ = std::make_unique<spatial_index_type>(16, 4);
    tree_->insert(values.begin(), values.end());
#endif
}

topojson_datasource::~topojson_datasource() { }

const char * topojson_datasource::name()
{
    return "topojson";
}

boost::optional<mapnik::datasource::geometry_t> topojson_datasource::get_geometry_type() const
{
    boost::optional<mapnik::datasource::geometry_t> result;
    int multi_type = 0;
    std::size_t num_features = topo_.geometries.size();
    for (std::size_t i = 0; i < num_features && i < 5; ++i)
    {
        mapnik::topojson::geometry const& geom = topo_.geometries[i];
        int type = mapnik::util::apply_visitor(geometry_type_visitor(),geom);
        if (type > 0)
        {
            if (multi_type > 0 && multi_type != type)
            {
                result.reset(mapnik::datasource::Collection);
                return result;
            }
            else
            {
                result.reset(static_cast<mapnik::datasource::geometry_t>(type));
            }
            multi_type = type;
        }
    }
    return result;
}

mapnik::datasource::datasource_t topojson_datasource::type() const
{
    return type_;
}

mapnik::box2d<double> topojson_datasource::envelope() const
{
    return extent_;
}

mapnik::layer_descriptor topojson_datasource::get_descriptor() const
{
    return desc_;
}

mapnik::featureset_ptr topojson_datasource::features(mapnik::query const& q) const
{
    // if the query box intersects our world extent then query for features
    mapnik::box2d<double> const& b = q.get_bbox();
    if (extent_.intersects(b))
    {
        box_type box(point_type(b.minx(),b.miny()),point_type(b.maxx(),b.maxy()));
#if BOOST_VERSION >= 105600
        topojson_featureset::array_type index_array;
        if (tree_)
        {
            tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array));
            return std::make_shared<topojson_featureset>(topo_, *tr_, std::move(index_array));
        }
#else
        if (tree_)
        {
            return std::make_shared<topojson_featureset>(topo_, *tr_, tree_.find(box));
        }
#endif
    }
    // otherwise return an empty featureset pointer
    return mapnik::featureset_ptr();
}

mapnik::featureset_ptr topojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
    mapnik::box2d<double> query_bbox(pt, pt);
    query_bbox.pad(tol);
    mapnik::query q(query_bbox);
    for (auto const& attr_info : desc_.get_descriptors())
    {
        q.add_property_name(attr_info.get_name());
    }
    return features(q);
}
<commit_msg>fix typo :)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "topojson_datasource.hpp"
#include "topojson_featureset.hpp"

#include <fstream>
#include <algorithm>

// boost

#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>

// mapnik
#include <mapnik/unicode.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/json/topojson_grammar.hpp>
#include <mapnik/json/topojson_grammar_impl.hpp>
#include <mapnik/json/topojson_utils.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/make_unique.hpp>

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(topojson_datasource)

struct attr_value_converter : public mapnik::util::static_visitor<mapnik::eAttributeType>
{
    mapnik::eAttributeType operator() (mapnik::value_integer /*val*/) const
    {
        return mapnik::Integer;
    }

    mapnik::eAttributeType operator() (double /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (float /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (bool /*val*/) const
    {
        return mapnik::Boolean;
    }

    mapnik::eAttributeType operator() (std::string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_unicode_string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_null const& /*val*/) const
    {
        return mapnik::String;
    }
};

struct geometry_type_visitor : public mapnik::util::static_visitor<int>
{
    int operator() (mapnik::topojson::point const&) const
    {
        return static_cast<int>(mapnik::datasource::Point);
    }
    int operator() (mapnik::topojson::multi_point const&) const
    {
        return static_cast<int>(mapnik::datasource::Point);
    }
    int operator() (mapnik::topojson::linestring const&) const
    {
        return static_cast<int>(mapnik::datasource::LineString);
    }
    int operator() (mapnik::topojson::multi_linestring const&) const
    {
        return static_cast<int>(mapnik::datasource::LineString);
    }
    int operator() (mapnik::topojson::polygon const&) const
    {
        return static_cast<int>(mapnik::datasource::Polygon);
    }
    int operator() (mapnik::topojson::multi_polygon const&) const
    {
        return static_cast<int>(mapnik::datasource::Polygon);
    }
    int operator() (mapnik::topojson::invalid const&) const
    {
        return -1;
    }
};

struct collect_attributes_visitor : public mapnik::util::static_visitor<void>
{
    mapnik::layer_descriptor & desc_;
    collect_attributes_visitor(mapnik::layer_descriptor & desc):
      desc_(desc) {}

    void operator() (mapnik::topojson::invalid const& g) {}

    template <typename GeomType>
    void operator() (GeomType const& g)
    {
        if (g.props)
        {
            for (auto const& p : *g.props)
            {
                desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(p),
                                                                  mapnik::util::apply_visitor(attr_value_converter(),
                                                                                std::get<1>(p))));
            }
        }
    }
};

topojson_datasource::topojson_datasource(parameters const& params)
  : datasource(params),
    type_(datasource::Vector),
    desc_(topojson_datasource::name(),
          *params.get<std::string>("encoding","utf-8")),
    filename_(),
    inline_string_(),
    extent_(),
    tr_(new mapnik::transcoder(*params.get<std::string>("encoding","utf-8"))),
    tree_(nullptr)
{
    boost::optional<std::string> inline_string = params.get<std::string>("inline");
    if (inline_string)
    {
        inline_string_ = *inline_string;
    }
    else
    {
        boost::optional<std::string> file = params.get<std::string>("file");
        if (!file) throw mapnik::datasource_exception("TopoJSON Plugin: missing <file> parameter");

        boost::optional<std::string> base = params.get<std::string>("base");
        if (base)
            filename_ = *base + "/" + *file;
        else
            filename_ = *file;
    }
    if (!inline_string_.empty())
    {
        std::istringstream in(inline_string_);
        parse_topojson(in);
    }
    else
    {
#if defined (_WINDOWS)
        std::ifstream in(mapnik::utf8_to_utf16(filename_),std::ios_base::in | std::ios_base::binary);
#else
        std::ifstream in(filename_.c_str(),std::ios_base::in | std::ios_base::binary);
#endif
        if (!in.is_open())
        {
            throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'");
        }
        parse_topojson(in);
        in.close();
    }
}

template <typename T>
void topojson_datasource::parse_topojson(T & stream)
{
    using base_iterator_type = std::istreambuf_iterator<char>;
    boost::spirit::multi_pass<base_iterator_type> begin =
        boost::spirit::make_default_multi_pass(base_iterator_type(stream));

    boost::spirit::multi_pass<base_iterator_type> end =
        boost::spirit::make_default_multi_pass(base_iterator_type());

    static const mapnik::topojson::topojson_grammar<boost::spirit::multi_pass<base_iterator_type> > g;
    boost::spirit::standard_wide::space_type space;
    bool result = boost::spirit::qi::phrase_parse(begin, end, g, space, topo_);
    if (!result)
    {
        throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + filename_ + "'");
    }

    using values_container = std::vector< std::pair<box_type, std::size_t> >;
    values_container values;
    values.reserve(topo_.geometries.size());
    std::size_t geometry_index = 0;

    for (auto const& geom : topo_.geometries)
    {
        mapnik::box2d<double> box = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo_), geom);
        if (box.valid())
        {
            if (geometry_index == 0)
            {
                extent_ = box;
                collect_attributes_visitor assessor(desc_);
                mapnik::util::apply_visitor( std::ref(assessor), geom);
            }
            else
            {
                extent_.expand_to_include(box);
            }
        }
#if BOOST_VERSION >= 105600
        values.emplace_back(box_type(point_type(box.minx(),box.miny()),point_type(box.maxx(),box.maxy())), geometry_index);
#else
        values.emplace_back(box_type(point_type(box.minx(),box.miny()),point_type(box.maxx(),box.maxy())),geometry_index);
#endif
        ++geometry_index;
    }

#if BOOST_VERSION >= 105600
    // packing algorithm
    tree_ = std::make_unique<spatial_index_type>(values);
#else
    tree_ = std::make_unique<spatial_index_type>(16, 4);
    tree_->insert(values.begin(), values.end());
#endif
}

topojson_datasource::~topojson_datasource() { }

const char * topojson_datasource::name()
{
    return "topojson";
}

boost::optional<mapnik::datasource::geometry_t> topojson_datasource::get_geometry_type() const
{
    boost::optional<mapnik::datasource::geometry_t> result;
    int multi_type = 0;
    std::size_t num_features = topo_.geometries.size();
    for (std::size_t i = 0; i < num_features && i < 5; ++i)
    {
        mapnik::topojson::geometry const& geom = topo_.geometries[i];
        int type = mapnik::util::apply_visitor(geometry_type_visitor(),geom);
        if (type > 0)
        {
            if (multi_type > 0 && multi_type != type)
            {
                result.reset(mapnik::datasource::Collection);
                return result;
            }
            else
            {
                result.reset(static_cast<mapnik::datasource::geometry_t>(type));
            }
            multi_type = type;
        }
    }
    return result;
}

mapnik::datasource::datasource_t topojson_datasource::type() const
{
    return type_;
}

mapnik::box2d<double> topojson_datasource::envelope() const
{
    return extent_;
}

mapnik::layer_descriptor topojson_datasource::get_descriptor() const
{
    return desc_;
}

mapnik::featureset_ptr topojson_datasource::features(mapnik::query const& q) const
{
    // if the query box intersects our world extent then query for features
    mapnik::box2d<double> const& b = q.get_bbox();
    if (extent_.intersects(b))
    {
        box_type box(point_type(b.minx(),b.miny()),point_type(b.maxx(),b.maxy()));
#if BOOST_VERSION >= 105600
        topojson_featureset::array_type index_array;
        if (tree_)
        {
            tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array));
            return std::make_shared<topojson_featureset>(topo_, *tr_, std::move(index_array));
        }
#else
        if (tree_)
        {
            return std::make_shared<topojson_featureset>(topo_, *tr_, tree_->find(box));
        }
#endif
    }
    // otherwise return an empty featureset pointer
    return mapnik::featureset_ptr();
}

mapnik::featureset_ptr topojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
    mapnik::box2d<double> query_bbox(pt, pt);
    query_bbox.pad(tol);
    mapnik::query q(query_bbox);
    for (auto const& attr_info : desc_.get_descriptors())
    {
        q.add_property_name(attr_info.get_name());
    }
    return features(q);
}
<|endoftext|>


<commit_before>/*
    This file is part of kdepim.

    Copyright (c) 2004 Till Adam <adam@kde.org>

    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.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <interfaces/bodypartformatter.h>
#include <interfaces/bodypart.h>
#include <interfaces/bodyparturlhandler.h>
#include <khtmlparthtmlwriter.h>

#include <kmail/callback.h>
#include <kmail/kmmessage.h>

#include <kglobal.h>
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kapplication.h>

#include <qurl.h>
#include <qfile.h>
#include <qdir.h>
#include <qstylesheet.h>

namespace {

  // TODO: Show filename header to make it possible to save the patch.
  // FIXME: The box should only be as wide as necessary.

  class Formatter : public KMail::Interface::BodyPartFormatter {
  public:
    Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {

      if ( !writer ) return Ok;

      if (  bodyPart->defaultDisplay() == KMail::Interface::BodyPart::AsIcon )
        return AsIcon;

      const QString diff = bodyPart->asText();
      if ( diff.isEmpty() ) return AsIcon;

      QString addedLineStyle = QString::fromLatin1(
        "style=\""
        "color: green;\"");
      QString fileAddStyle( "style=\"font-weight: bold; "
                            "color: green; \"" );

      QString removedLineStyle = QString::fromLatin1(
        "style=\""
        "color: red;\"");
      QString fileRemoveStyle( "style=\"font-weight: bold; "
                               "color: red ;\"" );

      QString tableStyle = QString::fromLatin1(
        "style=\""
        "border: solid black 1px; "
        "padding: 0.5em; "
        "margin: 0em;\"");

      QString sepStyle( "style=\"color: black; font-weight: bold;\"" );
      QString chunkStyle( "style=\"color: blue;\"" );

      QString html = "

";
      html += "
";

      QStringList lines = QStringList::split( '\n', diff, true );
      for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
        QString line( QStyleSheet::escape( *it ) );
        QString style;
        if ( line.length() > 0 ) {
          if ( line.startsWith( "+++" ) ) {
            style = fileAddStyle;
          } else if ( line.startsWith( "---" ) ) {
            style = fileRemoveStyle;
          } else if ( line.startsWith( "+" ) || line.startsWith( ">" ) ) {
            style = addedLineStyle;
          } else if ( line.startsWith( "-" ) || line.startsWith( "<" ) ) {
            style = removedLineStyle;
          } else if ( line.startsWith( "==") ) {
            style = sepStyle;
          } else if ( line.startsWith( "@@" ) ) {
            style = chunkStyle;
          } else {
            style = "";
          }
        }
        html += "" + line + "\n";
      }

      html += "

";
      //qDebug( "%s", html.latin1() );
      writer->queue( html );

      return Ok;
    }
  };

  class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
  public:
    const KMail::Interface::BodyPartFormatter * bodyPartFormatter( int idx ) const {
      return idx == 0 ? new Formatter() : 0 ;
    }
    const char * type( int idx ) const {
      return idx == 0 ? "text" : 0 ;
    }
    const char * subtype( int idx ) const {
      return idx == 0 ? "x-diff" : 0 ;
    }

    const KMail::Interface::BodyPartURLHandler * urlHandler( int ) const { return 0; }
  };

}

extern "C"
KMail::Interface::BodyPartFormatterPlugin *
libkmail_bodypartformatter_text_xdiff_create_bodypart_formatter_plugin() {
  return new Plugin();
}
<commit_msg>Fix line breaks in empty or whitespace-only lines.<commit_after>/*
    This file is part of kdepim.

    Copyright (c) 2004 Till Adam <adam@kde.org>

    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.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <interfaces/bodypartformatter.h>
#include <interfaces/bodypart.h>
#include <interfaces/bodyparturlhandler.h>
#include <khtmlparthtmlwriter.h>

#include <kmail/callback.h>
#include <kmail/kmmessage.h>

#include <kglobal.h>
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kapplication.h>

#include <qurl.h>
#include <qfile.h>
#include <qdir.h>
#include <qstylesheet.h>

namespace {

  // TODO: Show filename header to make it possible to save the patch.
  // FIXME: The box should only be as wide as necessary.

  class Formatter : public KMail::Interface::BodyPartFormatter {
  public:
    Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {

      if ( !writer ) return Ok;

      if (  bodyPart->defaultDisplay() == KMail::Interface::BodyPart::AsIcon )
        return AsIcon;

      const QString diff = bodyPart->asText();
      if ( diff.isEmpty() ) return AsIcon;

      QString addedLineStyle = QString::fromLatin1(
        "style=\""
        "color: green;\"");
      QString fileAddStyle( "style=\"font-weight: bold; "
                            "color: green; \"" );

      QString removedLineStyle = QString::fromLatin1(
        "style=\""
        "color: red;\"");
      QString fileRemoveStyle( "style=\"font-weight: bold; "
                               "color: red ;\"" );

      QString tableStyle = QString::fromLatin1(
        "style=\""
        "border: solid black 1px; "
        "padding: 0.5em; "
        "margin: 0em;\"");

      QString sepStyle( "style=\"color: black; font-weight: bold;\"" );
      QString chunkStyle( "style=\"color: blue;\"" );

      QString html = "

";
      html += "
";

      QStringList lines = QStringList::split( '\n', diff, true );
      for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
        QString line( QStyleSheet::escape( *it ) );
        QString style;
        if ( line.length() > 0 ) {
          if ( line.startsWith( "+++" ) ) {
            style = fileAddStyle;
          } else if ( line.startsWith( "---" ) ) {
            style = fileRemoveStyle;
          } else if ( line.startsWith( "+" ) || line.startsWith( ">" ) ) {
            style = addedLineStyle;
          } else if ( line.startsWith( "-" ) || line.startsWith( "<" ) ) {
            style = removedLineStyle;
          } else if ( line.startsWith( "==") ) {
            style = sepStyle;
          } else if ( line.startsWith( "@@" ) ) {
            style = chunkStyle;
          } else {
            style = "";
          }
        }
        html += "" + line + "
";
      }

      html += "

";
      //qDebug( "%s", html.latin1() );
      writer->queue( html );

      return Ok;
    }
  };

  class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
  public:
    const KMail::Interface::BodyPartFormatter * bodyPartFormatter( int idx ) const {
      return idx == 0 ? new Formatter() : 0 ;
    }
    const char * type( int idx ) const {
      return idx == 0 ? "text" : 0 ;
    }
    const char * subtype( int idx ) const {
      return idx == 0 ? "x-diff" : 0 ;
    }

    const KMail::Interface::BodyPartURLHandler * urlHandler( int ) const { return 0; }
  };

}

extern "C"
KMail::Interface::BodyPartFormatterPlugin *
libkmail_bodypartformatter_text_xdiff_create_bodypart_formatter_plugin() {
  return new Plugin();
}
<|endoftext|>


<commit_before>#include "PlayState.h"
#include <iostream>
#include "TextureManager.h"
#include "Game.h"
#include "Player.h"
#include "Enemy.h"
#include "InputHandler.h"
#include "PauseState.h"

const std::string PlayState::s_playID = "PLAY";

void PlayState::update()
{
	//listen for ESC key to pause the game
	if (TheInputHandler::Instance()->isKeyDown(SDL_SCANCODE_ESCAPE))
	{
		TheGame::Instance()->getStateMachine()->pushState(new PauseState());
	}

	for (int i = 0; i < m_gameObjects.size(); ++i)
	{
		m_gameObjects[i]->update();
	}
}

void PlayState::render()
{
	for (int i = 0; i < m_gameObjects.size(); ++i)
	{
		m_gameObjects[i]->draw();
	}
}

bool PlayState::onEnter()
{
	if (!TheTextureManager::Instance()->load("assets/helicopter.png", "helicopter", TheGame::Instance()->getRenderer()))
	{
		return false;
	}

	if (!TheTextureManager::Instance()->load("assets/helicopter2.png", "helicopter2", TheGame::Instance()->getRenderer()))
	{
		return false;
	}

	GameObject* player = new Player(new LoaderParams(500, 100, 128, 55, "helicopter"));
	GameObject* enemy = new Enemy(new LoaderParams(100, 100, 128, 55, "helicopter2"));

	m_gameObjects.push_back(player);
	m_gameObjects.push_back(enemy);

	std::cout << "entering PlayState\n";
	return true;
}

bool PlayState::onExit()
{
	for (int i = 0; i < m_gameObjects.size(); ++i)
	{
		m_gameObjects[i]->clean();
	}
	m_gameObjects.clear();
	TheTextureManager::Instance()->clearFromTextureMap("helicopter");

	std::cout << "exiting PlayState\n";
	return true;
}<commit_msg>Updated call to LoaderParams() in PlayState.cpp<commit_after>#include "PlayState.h"
#include <iostream>
#include "TextureManager.h"
#include "Game.h"
#include "Player.h"
#include "Enemy.h"
#include "InputHandler.h"
#include "PauseState.h"

const std::string PlayState::s_playID = "PLAY";

void PlayState::update()
{
	//listen for ESC key to pause the game
	if (TheInputHandler::Instance()->isKeyDown(SDL_SCANCODE_ESCAPE))
	{
		TheGame::Instance()->getStateMachine()->pushState(new PauseState());
	}

	for (int i = 0; i < m_gameObjects.size(); ++i)
	{
		m_gameObjects[i]->update();
	}
}

void PlayState::render()
{
	for (int i = 0; i < m_gameObjects.size(); ++i)
	{
		m_gameObjects[i]->draw();
	}
}

bool PlayState::onEnter()
{
	if (!TheTextureManager::Instance()->load("assets/helicopter.png", "helicopter", TheGame::Instance()->getRenderer()))
	{
		return false;
	}

	if (!TheTextureManager::Instance()->load("assets/helicopter2.png", "helicopter2", TheGame::Instance()->getRenderer()))
	{
		return false;
	}

	GameObject* player = new Player(new LoaderParams(500, 100, 128, 55, 5, "helicopter"));
	GameObject* enemy = new Enemy(new LoaderParams(100, 100, 128, 55, 5, "helicopter2"));

	m_gameObjects.push_back(player);
	m_gameObjects.push_back(enemy);

	std::cout << "entering PlayState\n";
	return true;
}

bool PlayState::onExit()
{
	for (int i = 0; i < m_gameObjects.size(); ++i)
	{
		m_gameObjects[i]->clean();
	}
	m_gameObjects.clear();
	TheTextureManager::Instance()->clearFromTextureMap("helicopter");

	std::cout << "exiting PlayState\n";
	return true;
}<|endoftext|>


<commit_before>/**
 * @file llfloatergroups.cpp
 * @brief LLPanelGroups class implementation
 *
 * $LicenseInfo:firstyear=2002&license=viewergpl$
 *
 * Copyright (c) 2002-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

/*
 * Shown from Edit -> Groups...
 * Shows the agent's groups and allows the edit window to be invoked.
 * Also overloaded to allow picking of a single group for assigning
 * objects and land to groups.
 */

#include "llviewerprecompiledheaders.h"

#include "llfloatergroups.h"

#include "roles_constants.h"

#include "llagent.h"
#include "llbutton.h"
#include "llgroupactions.h"
#include "llscrolllistctrl.h"
#include "lltextbox.h"
#include "lluictrlfactory.h"
#include "lltrans.h"

using namespace LLOldEvents;

// helper functions
void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 powers_mask = GP_ALL_POWERS);

///----------------------------------------------------------------------------
/// Class LLFloaterGroupPicker
///----------------------------------------------------------------------------

LLFloaterGroupPicker::LLFloaterGroupPicker(const LLSD& seed)
: 	LLFloater(seed),
	mPowersMask(GP_ALL_POWERS),
	mID(seed.asUUID())
{
// 	LLUICtrlFactory::getInstance()->buildFloater(this, "floater_choose_group.xml");
}

LLFloaterGroupPicker::~LLFloaterGroupPicker()
{
}

void LLFloaterGroupPicker::setPowersMask(U64 powers_mask)
{
	mPowersMask = powers_mask;
	postBuild();
}

BOOL LLFloaterGroupPicker::postBuild()
{
	LLScrollListCtrl* list_ctrl = getChild<LLScrollListCtrl>("group list");
	if (list_ctrl)
	{
		init_group_list(list_ctrl, gAgent.getGroupID(), mPowersMask);
		list_ctrl->setDoubleClickCallback(onBtnOK, this);
		list_ctrl->setContextMenu(LLScrollListCtrl::MENU_GROUP);
	}

	childSetAction("OK", onBtnOK, this);

	childSetAction("Cancel", onBtnCancel, this);

	setDefaultBtn("OK");

	childEnable("OK");

	return TRUE;
}

void LLFloaterGroupPicker::removeNoneOption()
{
	// Remove group "none" from list. Group "none" is added in init_group_list().
	// Some UI elements use group "none", we need to manually delete it here.
	// Group "none" ID is LLUUID:null.
	LLCtrlListInterface* group_list = getChild<LLScrollListCtrl>("group list")->getListInterface();
	if(group_list)
	{
		group_list->selectByValue(LLUUID::null);
		group_list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
	}
}

void LLFloaterGroupPicker::onBtnOK(void* userdata)
{
	LLFloaterGroupPicker* self = (LLFloaterGroupPicker*)userdata;
	if(self) self->ok();
}

void LLFloaterGroupPicker::onBtnCancel(void* userdata)
{
	LLFloaterGroupPicker* self = (LLFloaterGroupPicker*)userdata;
	if(self) self->closeFloater();
}

void LLFloaterGroupPicker::ok()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list)
	{
		group_id = group_list->getCurrentID();
	}
	mGroupSelectSignal(group_id);

	closeFloater();
}

///----------------------------------------------------------------------------
/// Class LLPanelGroups
///----------------------------------------------------------------------------

//LLEventListener
//virtual
bool LLPanelGroups::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
	if (event->desc() == "new group")
	{
		reset();
		return true;
	}
	return false;
}

// Default constructor
LLPanelGroups::LLPanelGroups() :
	LLPanel()
{
	gAgent.addListener(this, "new group");
}

LLPanelGroups::~LLPanelGroups()
{
	gAgent.removeListener(this);
}

// clear the group list, and get a fresh set of info.
void LLPanelGroups::reset()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	if (group_list)
	{
		group_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
	}
	childSetTextArg("groupcount", "[COUNT]", llformat("%d",gAgent.mGroups.count()));
	childSetTextArg("groupcount", "[MAX]", llformat("%d",MAX_AGENT_GROUPS));

	init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID());
	enableButtons();
}

BOOL LLPanelGroups::postBuild()
{
	childSetCommitCallback("group list", onGroupList, this);

	childSetTextArg("groupcount", "[COUNT]", llformat("%d",gAgent.mGroups.count()));
	childSetTextArg("groupcount", "[MAX]", llformat("%d",MAX_AGENT_GROUPS));

	LLScrollListCtrl *list = getChild<LLScrollListCtrl>("group list");
	if (list)
	{
		init_group_list(list, gAgent.getGroupID());
		list->setDoubleClickCallback(onBtnIM, this);
		list->setContextMenu(LLScrollListCtrl::MENU_GROUP);
	}

	childSetAction("Activate", onBtnActivate, this);

	childSetAction("Info", onBtnInfo, this);

	childSetAction("IM", onBtnIM, this);

	childSetAction("Leave", onBtnLeave, this);

	childSetAction("Create", onBtnCreate, this);

	childSetAction("Search...", onBtnSearch, this);

	setDefaultBtn("IM");

	reset();

	return TRUE;
}

void LLPanelGroups::enableButtons()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list)
	{
		group_id = group_list->getCurrentID();
	}

	if(group_id != gAgent.getGroupID())
	{
		childEnable("Activate");
	}
	else
	{
		childDisable("Activate");
	}
	if (group_id.notNull())
	{
		childEnable("Info");
		childEnable("IM");
		childEnable("Leave");
	}
	else
	{
		childDisable("Info");
		childDisable("IM");
		childDisable("Leave");
	}
	childSetEnabled("Create", gAgent.canJoinGroups());
}

void LLPanelGroups::onBtnCreate(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->create();
}

void LLPanelGroups::onBtnActivate(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->activate();
}

void LLPanelGroups::onBtnInfo(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->info();
}

void LLPanelGroups::onBtnIM(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->startIM();
}

void LLPanelGroups::onBtnLeave(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->leave();
}

void LLPanelGroups::onBtnSearch(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->search();
}

void LLPanelGroups::create()
{
	LLGroupActions::createGroup();
}

void LLPanelGroups::activate()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list)
	{
		group_id = group_list->getCurrentID();
	}
	LLGroupActions::activate(group_id);
}

void LLPanelGroups::info()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list && (group_id = group_list->getCurrentID()).notNull())
	{
		LLGroupActions::show(group_id);
	}
}

void LLPanelGroups::startIM()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;

	if (group_list && (group_id = group_list->getCurrentID()).notNull())
	{
		LLGroupActions::startIM(group_id);
	}
}

void LLPanelGroups::leave()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list && (group_id = group_list->getCurrentID()).notNull())
	{
		LLGroupActions::leave(group_id);
	}
}

void LLPanelGroups::search()
{
	LLGroupActions::search();
}

void LLPanelGroups::onGroupList(LLUICtrl* ctrl, void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->enableButtons();
}

void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 powers_mask)
{
	S32 count = gAgent.mGroups.count();
	LLUUID id;
	LLCtrlListInterface *group_list = ctrl->getListInterface();
	if (!group_list) return;

	group_list->operateOnAll(LLCtrlListInterface::OP_DELETE);

	for(S32 i = 0; i < count; ++i)
	{
		id = gAgent.mGroups.get(i).mID;
		LLGroupData* group_datap = &gAgent.mGroups.get(i);
		if ((powers_mask == GP_ALL_POWERS) || ((group_datap->mPowers & powers_mask) != 0))
		{
			std::string style = "NORMAL";
			if(highlight_id == id)
			{
				style = "BOLD";
			}

			LLSD element;
			element["id"] = id;
			element["columns"][0]["column"] = "name";
			element["columns"][0]["value"] = group_datap->mName;
			element["columns"][0]["font"]["name"] = "SANSSERIF";
			element["columns"][0]["font"]["style"] = style;

			group_list->addElement(element, ADD_SORTED);
		}
	}

	// add "none" to list at top
	{
		std::string style = "NORMAL";
		if (highlight_id.isNull())
		{
			style = "BOLD";
		}
		LLSD element;
		element["id"] = LLUUID::null;
		element["columns"][0]["column"] = "name";
		element["columns"][0]["value"] = LLTrans::getString("GroupsNone");
		element["columns"][0]["font"]["name"] = "SANSSERIF";
		element["columns"][0]["font"]["style"] = style;

		group_list->addElement(element, ADD_TOP);
	}

	group_list->selectByValue(highlight_id);
}

<commit_msg>Fixed bug EXT-4580 (Duplicated avatar's name appears in 'Group invitation' floater if use context menu for invitation). Because duplicated postBuild() calls, the "OK" button callback was set and *called* twice.<commit_after>/**
 * @file llfloatergroups.cpp
 * @brief LLPanelGroups class implementation
 *
 * $LicenseInfo:firstyear=2002&license=viewergpl$
 *
 * Copyright (c) 2002-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

/*
 * Shown from Edit -> Groups...
 * Shows the agent's groups and allows the edit window to be invoked.
 * Also overloaded to allow picking of a single group for assigning
 * objects and land to groups.
 */

#include "llviewerprecompiledheaders.h"

#include "llfloatergroups.h"

#include "roles_constants.h"

#include "llagent.h"
#include "llbutton.h"
#include "llgroupactions.h"
#include "llscrolllistctrl.h"
#include "lltextbox.h"
#include "lluictrlfactory.h"
#include "lltrans.h"

using namespace LLOldEvents;

// helper functions
void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 powers_mask = GP_ALL_POWERS);

///----------------------------------------------------------------------------
/// Class LLFloaterGroupPicker
///----------------------------------------------------------------------------

LLFloaterGroupPicker::LLFloaterGroupPicker(const LLSD& seed)
: 	LLFloater(seed),
	mPowersMask(GP_ALL_POWERS),
	mID(seed.asUUID())
{
// 	LLUICtrlFactory::getInstance()->buildFloater(this, "floater_choose_group.xml");
}

LLFloaterGroupPicker::~LLFloaterGroupPicker()
{
}

void LLFloaterGroupPicker::setPowersMask(U64 powers_mask)
{
	mPowersMask = powers_mask;
	init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID(), mPowersMask);
}

BOOL LLFloaterGroupPicker::postBuild()
{
	LLScrollListCtrl* list_ctrl = getChild<LLScrollListCtrl>("group list");
	if (list_ctrl)
	{
		init_group_list(list_ctrl, gAgent.getGroupID(), mPowersMask);
		list_ctrl->setDoubleClickCallback(onBtnOK, this);
		list_ctrl->setContextMenu(LLScrollListCtrl::MENU_GROUP);
	}

	childSetAction("OK", onBtnOK, this);

	childSetAction("Cancel", onBtnCancel, this);

	setDefaultBtn("OK");

	childEnable("OK");

	return TRUE;
}

void LLFloaterGroupPicker::removeNoneOption()
{
	// Remove group "none" from list. Group "none" is added in init_group_list().
	// Some UI elements use group "none", we need to manually delete it here.
	// Group "none" ID is LLUUID:null.
	LLCtrlListInterface* group_list = getChild<LLScrollListCtrl>("group list")->getListInterface();
	if(group_list)
	{
		group_list->selectByValue(LLUUID::null);
		group_list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
	}
}

void LLFloaterGroupPicker::onBtnOK(void* userdata)
{
	LLFloaterGroupPicker* self = (LLFloaterGroupPicker*)userdata;
	if(self) self->ok();
}

void LLFloaterGroupPicker::onBtnCancel(void* userdata)
{
	LLFloaterGroupPicker* self = (LLFloaterGroupPicker*)userdata;
	if(self) self->closeFloater();
}

void LLFloaterGroupPicker::ok()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list)
	{
		group_id = group_list->getCurrentID();
	}
	mGroupSelectSignal(group_id);

	closeFloater();
}

///----------------------------------------------------------------------------
/// Class LLPanelGroups
///----------------------------------------------------------------------------

//LLEventListener
//virtual
bool LLPanelGroups::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
	if (event->desc() == "new group")
	{
		reset();
		return true;
	}
	return false;
}

// Default constructor
LLPanelGroups::LLPanelGroups() :
	LLPanel()
{
	gAgent.addListener(this, "new group");
}

LLPanelGroups::~LLPanelGroups()
{
	gAgent.removeListener(this);
}

// clear the group list, and get a fresh set of info.
void LLPanelGroups::reset()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	if (group_list)
	{
		group_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
	}
	childSetTextArg("groupcount", "[COUNT]", llformat("%d",gAgent.mGroups.count()));
	childSetTextArg("groupcount", "[MAX]", llformat("%d",MAX_AGENT_GROUPS));

	init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID());
	enableButtons();
}

BOOL LLPanelGroups::postBuild()
{
	childSetCommitCallback("group list", onGroupList, this);

	childSetTextArg("groupcount", "[COUNT]", llformat("%d",gAgent.mGroups.count()));
	childSetTextArg("groupcount", "[MAX]", llformat("%d",MAX_AGENT_GROUPS));

	LLScrollListCtrl *list = getChild<LLScrollListCtrl>("group list");
	if (list)
	{
		init_group_list(list, gAgent.getGroupID());
		list->setDoubleClickCallback(onBtnIM, this);
		list->setContextMenu(LLScrollListCtrl::MENU_GROUP);
	}

	childSetAction("Activate", onBtnActivate, this);

	childSetAction("Info", onBtnInfo, this);

	childSetAction("IM", onBtnIM, this);

	childSetAction("Leave", onBtnLeave, this);

	childSetAction("Create", onBtnCreate, this);

	childSetAction("Search...", onBtnSearch, this);

	setDefaultBtn("IM");

	reset();

	return TRUE;
}

void LLPanelGroups::enableButtons()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list)
	{
		group_id = group_list->getCurrentID();
	}

	if(group_id != gAgent.getGroupID())
	{
		childEnable("Activate");
	}
	else
	{
		childDisable("Activate");
	}
	if (group_id.notNull())
	{
		childEnable("Info");
		childEnable("IM");
		childEnable("Leave");
	}
	else
	{
		childDisable("Info");
		childDisable("IM");
		childDisable("Leave");
	}
	childSetEnabled("Create", gAgent.canJoinGroups());
}

void LLPanelGroups::onBtnCreate(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->create();
}

void LLPanelGroups::onBtnActivate(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->activate();
}

void LLPanelGroups::onBtnInfo(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->info();
}

void LLPanelGroups::onBtnIM(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->startIM();
}

void LLPanelGroups::onBtnLeave(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->leave();
}

void LLPanelGroups::onBtnSearch(void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->search();
}

void LLPanelGroups::create()
{
	LLGroupActions::createGroup();
}

void LLPanelGroups::activate()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list)
	{
		group_id = group_list->getCurrentID();
	}
	LLGroupActions::activate(group_id);
}

void LLPanelGroups::info()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list && (group_id = group_list->getCurrentID()).notNull())
	{
		LLGroupActions::show(group_id);
	}
}

void LLPanelGroups::startIM()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;

	if (group_list && (group_id = group_list->getCurrentID()).notNull())
	{
		LLGroupActions::startIM(group_id);
	}
}

void LLPanelGroups::leave()
{
	LLCtrlListInterface *group_list = childGetListInterface("group list");
	LLUUID group_id;
	if (group_list && (group_id = group_list->getCurrentID()).notNull())
	{
		LLGroupActions::leave(group_id);
	}
}

void LLPanelGroups::search()
{
	LLGroupActions::search();
}

void LLPanelGroups::onGroupList(LLUICtrl* ctrl, void* userdata)
{
	LLPanelGroups* self = (LLPanelGroups*)userdata;
	if(self) self->enableButtons();
}

void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 powers_mask)
{
	S32 count = gAgent.mGroups.count();
	LLUUID id;
	LLCtrlListInterface *group_list = ctrl->getListInterface();
	if (!group_list) return;

	group_list->operateOnAll(LLCtrlListInterface::OP_DELETE);

	for(S32 i = 0; i < count; ++i)
	{
		id = gAgent.mGroups.get(i).mID;
		LLGroupData* group_datap = &gAgent.mGroups.get(i);
		if ((powers_mask == GP_ALL_POWERS) || ((group_datap->mPowers & powers_mask) != 0))
		{
			std::string style = "NORMAL";
			if(highlight_id == id)
			{
				style = "BOLD";
			}

			LLSD element;
			element["id"] = id;
			element["columns"][0]["column"] = "name";
			element["columns"][0]["value"] = group_datap->mName;
			element["columns"][0]["font"]["name"] = "SANSSERIF";
			element["columns"][0]["font"]["style"] = style;

			group_list->addElement(element, ADD_SORTED);
		}
	}

	// add "none" to list at top
	{
		std::string style = "NORMAL";
		if (highlight_id.isNull())
		{
			style = "BOLD";
		}
		LLSD element;
		element["id"] = LLUUID::null;
		element["columns"][0]["column"] = "name";
		element["columns"][0]["value"] = LLTrans::getString("GroupsNone");
		element["columns"][0]["font"]["name"] = "SANSSERIF";
		element["columns"][0]["font"]["style"] = style;

		group_list->addElement(element, ADD_TOP);
	}

	group_list->selectByValue(highlight_id);
}

<|endoftext|>


<commit_before>/*
    sim900.cpp
    A library for SeeedStudio seeeduino GPRS shield

    Copyright (c) 2015 seeed technology inc.
    Website    : www.seeed.cc
    Author     : lawliet zou
    Create Time: April 2015
    Change Log :

    The MIT License (MIT)

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/

#include "sim900.h"

SoftwareSerial* serialSIM900 = NULL;

void  sim900_init(void* uart_device, uint32_t baud) {
    serialSIM900 = (SoftwareSerial*)uart_device;
    serialSIM900->begin(baud);
}

int sim900_check_readable() {
    return serialSIM900->available();
}

int sim900_wait_readable(int wait_time) {
    unsigned long timerStart;
    int dataLen = 0;
    timerStart = millis();
    while ((unsigned long)(millis() - timerStart) > wait_time * 1000UL) {
        delay(500);
        dataLen = sim900_check_readable();
        if (dataLen > 0) {
            break;
        }
    }
    return dataLen;
}

void sim900_flush_serial() {
    while (sim900_check_readable()) {
        serialSIM900->read();
    }
}

void sim900_read_buffer(char* buffer, int count, unsigned int timeout, unsigned int chartimeout) {
    int i = 0;
    unsigned long timerStart, prevChar;
    timerStart = millis();
    prevChar = 0;
    while (1) {
        while (sim900_check_readable()) {
            char c = serialSIM900->read();
            prevChar = millis();
            buffer[i++] = c;
            DEBUG("-"); DEBUG(c);
            if (i >= count) {
                break;
            }
        }
        if (i >= count) {
            break;
        }
        if ((unsigned long)(millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long)(millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }
}

char* sim900_read_string_until(char* buffer, uint16_t count, const char* pattern, unsigned int timeout,
                               unsigned int chartimeout) {
    uint16_t i = 0;
    uint8_t sum = 0;
    uint8_t len = strlen(pattern);
    char* foundPtr = NULL;
    unsigned long timerStart, prevChar;

    timerStart = millis();
    prevChar = 0;
    while (1) {
        if (serialSIM900->available()) {
            char c = serialSIM900->read();
            DEBUG(c);
            prevChar = millis();
            buffer[i++] = c;

            sum = (c == pattern[sum]) ? sum + 1 : 0;

            if (sum == len) {
                foundPtr = &(buffer[i - len]);
                break;
            }
        }

        if (i >= count) {
            break;
        }

        if ((unsigned long)(millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long)(millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }

    return foundPtr;
}

void sim900_clean_buffer(char* buffer, int count) {
    for (int i = 0; i < count; i++) {
        buffer[i] = '\0';
    }
}

void sim900_send_byte(uint8_t data) {
    serialSIM900->write(data);
    DEBUG((char)data);
}

void sim900_send_char(const char c) {
    serialSIM900->write(c);
    DEBUG(c);
}

void sim900_send_cmd(const char* cmd) {
    for (uint16_t i = 0; i < strlen(cmd); i++) {
        sim900_send_byte(cmd[i]);
    }
}

void sim900_send_cmd(const __FlashStringHelper* cmd) {
    int i = 0;
    const char* ptr = (const char*) cmd;
    while (pgm_read_byte(ptr + i) != 0x00) {
        sim900_send_byte(pgm_read_byte(ptr + i++));
    }
}

void sim900_send_cmd_P(const char* cmd) {
    while (pgm_read_byte(cmd) != 0x00) {
        sim900_send_byte(pgm_read_byte(cmd++));
    }
}

boolean sim900_send_AT(void) {
    return sim900_check_with_cmd(F("AT\r\n"), "OK", CMD);
}

void sim900_send_End_Mark(void) {
    sim900_send_byte((char)26);
}

boolean sim900_wait_for_resp(const char* resp, DataType type, unsigned int timeout, unsigned int chartimeout) {
    int len = strlen(resp);
    int sum = 0;
    unsigned long timerStart, prevChar;    //prevChar is the time when the previous Char has been read.
    timerStart = millis();
    prevChar = 0;
    while (1) {
        if (sim900_check_readable()) {
            char c = serialSIM900->read();
            DEBUG("-");
            DEBUG(c);
            prevChar = millis();
            sum = (c == resp[sum]) ? sum + 1 : 0;
            if (sum == len) {
                break;
            }
        }
        if ((unsigned long)(millis() - timerStart) > timeout * 1000UL) {
            return false;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function.
        if (((unsigned long)(millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            return false;
        }

    }
    //If is a CMD, we will finish to read buffer.
    if (type == CMD) {
        sim900_flush_serial();
    }
    return true;
}

boolean sim900_check_with_cmd(const char* cmd, const char* resp, DataType type, unsigned int timeout,
                              unsigned int chartimeout) {
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp, type, timeout, chartimeout);
}

//HACERR que tambien la respuesta pueda ser FLASH STRING
boolean sim900_check_with_cmd(const __FlashStringHelper* cmd, const char* resp, DataType type, unsigned int timeout,
                              unsigned int chartimeout) {
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp, type, timeout, chartimeout);
}

void sim900_AT_bypass() {
    if (serialSIM900->available()) {
        Serial.write(serialSIM900->read());
    }
    if (Serial.available()) {
        serialSIM900->write(Serial.read());
    }
}<commit_msg>Fix typo in condition.<commit_after>/*
    sim900.cpp
    A library for SeeedStudio seeeduino GPRS shield

    Copyright (c) 2015 seeed technology inc.
    Website    : www.seeed.cc
    Author     : lawliet zou
    Create Time: April 2015
    Change Log :

    The MIT License (MIT)

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/

#include "sim900.h"

SoftwareSerial* serialSIM900 = NULL;

void  sim900_init(void* uart_device, uint32_t baud) {
    serialSIM900 = (SoftwareSerial*)uart_device;
    serialSIM900->begin(baud);
}

int sim900_check_readable() {
    return serialSIM900->available();
}

int sim900_wait_readable(int wait_time) {
    unsigned long timerStart;
    int dataLen = 0;
    timerStart = millis();
    while ((unsigned long)(millis() - timerStart) < wait_time * 1000UL) {
        delay(500);
        dataLen = sim900_check_readable();
        if (dataLen > 0) {
            break;
        }
    }
    return dataLen;
}

void sim900_flush_serial() {
    while (sim900_check_readable()) {
        serialSIM900->read();
    }
}

void sim900_read_buffer(char* buffer, int count, unsigned int timeout, unsigned int chartimeout) {
    int i = 0;
    unsigned long timerStart, prevChar;
    timerStart = millis();
    prevChar = 0;
    while (1) {
        while (sim900_check_readable()) {
            char c = serialSIM900->read();
            prevChar = millis();
            buffer[i++] = c;
            DEBUG("-"); DEBUG(c);
            if (i >= count) {
                break;
            }
        }
        if (i >= count) {
            break;
        }
        if ((unsigned long)(millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long)(millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }
}

char* sim900_read_string_until(char* buffer, uint16_t count, const char* pattern, unsigned int timeout,
                               unsigned int chartimeout) {
    uint16_t i = 0;
    uint8_t sum = 0;
    uint8_t len = strlen(pattern);
    char* foundPtr = NULL;
    unsigned long timerStart, prevChar;

    timerStart = millis();
    prevChar = 0;
    while (1) {
        if (serialSIM900->available()) {
            char c = serialSIM900->read();
            DEBUG(c);
            prevChar = millis();
            buffer[i++] = c;

            sum = (c == pattern[sum]) ? sum + 1 : 0;

            if (sum == len) {
                foundPtr = &(buffer[i - len]);
                break;
            }
        }

        if (i >= count) {
            break;
        }

        if ((unsigned long)(millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long)(millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }
    DEBUG("\n\n");

    return foundPtr;
}

void sim900_clean_buffer(char* buffer, int count) {
    for (int i = 0; i < count; i++) {
        buffer[i] = '\0';
    }
}

void sim900_send_byte(uint8_t data) {
    serialSIM900->write(data);
    DEBUG((char)data);
}

void sim900_send_char(const char c) {
    serialSIM900->write(c);
    DEBUG(c);
}

void sim900_send_cmd(const char* cmd) {
    for (uint16_t i = 0; i < strlen(cmd); i++) {
        sim900_send_byte(cmd[i]);
    }
}

void sim900_send_cmd(const __FlashStringHelper* cmd) {
    int i = 0;
    const char* ptr = (const char*) cmd;
    while (pgm_read_byte(ptr + i) != 0x00) {
        sim900_send_byte(pgm_read_byte(ptr + i++));
    }
}

void sim900_send_cmd_P(const char* cmd) {
    while (pgm_read_byte(cmd) != 0x00) {
        sim900_send_byte(pgm_read_byte(cmd++));
    }
}

boolean sim900_send_AT(void) {
    return sim900_check_with_cmd(F("AT\r\n"), "OK", CMD);
}

void sim900_send_End_Mark(void) {
    sim900_send_byte((char)26);
}

boolean sim900_wait_for_resp(const char* resp, DataType type, unsigned int timeout, unsigned int chartimeout) {
    int len = strlen(resp);
    int sum = 0;
    unsigned long timerStart, prevChar;    //prevChar is the time when the previous Char has been read.
    timerStart = millis();
    prevChar = 0;
    while (1) {
        if (sim900_check_readable()) {
            char c = serialSIM900->read();
            DEBUG("-");
            DEBUG(c);
            prevChar = millis();
            sum = (c == resp[sum]) ? sum + 1 : 0;
            if (sum == len) {
                break;
            }
        }
        if ((unsigned long)(millis() - timerStart) > timeout * 1000UL) {
            return false;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function.
        if (((unsigned long)(millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            return false;
        }

    }
    //If is a CMD, we will finish to read buffer.
    if (type == CMD) {
        sim900_flush_serial();
    }
    return true;
}

boolean sim900_check_with_cmd(const char* cmd, const char* resp, DataType type, unsigned int timeout,
                              unsigned int chartimeout) {
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp, type, timeout, chartimeout);
}

//HACERR que tambien la respuesta pueda ser FLASH STRING
boolean sim900_check_with_cmd(const __FlashStringHelper* cmd, const char* resp, DataType type, unsigned int timeout,
                              unsigned int chartimeout) {
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp, type, timeout, chartimeout);
}

void sim900_AT_bypass() {
    if (serialSIM900->available()) {
        Serial.write(serialSIM900->read());
    }
    if (Serial.available()) {
        serialSIM900->write(Serial.read());
    }
}
<|endoftext|>