пятница, 15 октября 2010 г.

Создание сервера закачек на базе торрент-клиента Deluge в Ubuntu

   Пару месяцев назад, я решил сделать сервер закачек на основе Deluge, которым можно было бы управлять удаленно. (с любого компьютера локальной сети или даже из инета). В процессе 'гугления' нашел в инете много материалов по настройке, однако, не все оказались одинаково полезны. Некоторые рецепты работают только в старых версиях ubuntu, другие предлагают написать мегаскрипты, часть описывают только запуск и настройку deluge. В итоге, набрав разных полезных и не очень материалов написал себе иснтрукцию по установке. Может кому еще пригодится...

Заходим в терминал.

Чтобы каждый раз не набирать sudo (получим временно права рута) пишем:
sudo -s наш_администратор

Устанавливаем deluge и веб морду командой:
apt-get install deluge deluge-webui

Добавляем нового пользователя:
adduser torrent

Запускаем:
visudo

добавлем в конец файла правило:
torrent ALL = NOPASSWD: /usr/bin/deluged
Сохраняем файл.

Переключаемся на пользователя torrent командой:
su torrent

Создаем директорию:
mkdir /home/torrent/scripts

Пишем небольшой скрипт в любом редакторе (vi, nano, gedit, medit...):
#!/bin/bash

sudo deluged
deluge -u web

Сохраняем его в директорию:
/home/torrent/scripts/deluge_auto.sh

Делаем файл исполняемым:
chmod a+x /home/torrent/scripts/deluge_auto.sh

(Этот скрипт будет запускать демона и deluged и 'веб-морду '.)

Далее настраиваем автоматический вход пользователя torrent в систему.
Идем в оболочке GNOME:
Система > Администрирование > Окно входа в систему > Безопасность
Ставим галочку в правильном месте и указываем пользователя torrent в нужном поле

Теперь добавим наш скрипт в автозапуск GNOME. Идем в Система->Параметры->Запускаемые приложения. Нажимаем кнопку добавить и заполняем формочку, в команде пишем путь до нашего скрипта:
/home/torrent/scripts/deluge_auto.sh

Имя ставим, например,
AutoRun Deluge.

Вообщем все. Теперь можно перезагрузится, и зайти на этот комп по сети через браузер написав:
http://ххх.ххх.ххх.ххх:8112
(где ххх.ххх.ххх.ххх ip адрес нашего сервера, а 8112 номер порта)

Если все хорошо, то появится форма с запросом пароля.
Вводим пароль: deluge
И попадаем в интерфейс Deluge. Далее идем config->password и меняем пароль доступа к Deluge. На этом установка и первоначальная настройка закончена!

Примечание:
Настройки Deluge также находятся ~/.config/deluge

четверг, 14 октября 2010 г.

Ubuntu:Как разрешить пользователю выполнять некоторые административные 'функции'/скрипты/программы.

     Часто возникает вопрос, как пользователю дать возможность выполнять некоторые административные ф-ии, которые изначально доступны только из под рута с применением команды sudo в Ubuntu. Например :

  • монтирование разделов/дисков
  • выключение/перезагрузка
  • запуск демонов (к примеру демона торрент сервиса - deluged)
  • запуск сервера apache без запроса пароля
  • запуск каких-то скриптов
  • и т.п.

      И так, для примера дадим права на выключение/перезагрузку и монтирование/размонтирование пользователю Vasya:

  • открываем терминал
  • набираем sudo -s ваш_аккаунт_администратора (sudo -s временно нам даcт права рута)
  • далее набираем visudo (откроется файл для редактирования sudoers)
  • Далее, добавляем в файл следующее:
vasya localhost = NOPASSWD: /usr/sbin/shutdown,/usr/sbin/reboot,/usr/bin/mount,/usr/bin/umount
  • сохраняем файл (если все хорошо с  синтаксисом, то файл благополучно сохраниться)
      Почему надо использовать visudo, а не просто редактировать файл sudoers? В первую очередь в целях безопасности т.к. visudo не сохранит изменения, если имеется синтаксическая ошибка. А изменения в этом файле являются критичными для работы пользователей и системы... visudo также гарантирует правку файла 'sudoers' только в одной сессии.


      Вот и всё. Аналогичным образом можно разрешить исполнение каких либо других скриптов или программ без запроса пароля. Только не забываем о безопасности, т.к. отключив запрос пароля для некоторых программ мы можем создать потенциальную дырку  в безопасности нашей системы из вне...

среда, 13 октября 2010 г.

SQL Query: Получение "уникальных" данных из БД

"Уникальных" это конечно сильно сказано... Дальше, я думаю, будет ясно о чем это я...

Дано:
Столбец 'emitent' таблицы 'deal' такого вида:
GAZP
ROSN
ROSN
VTB
ROSN
GMKN
GAZP
GMKN

Задача: Как получить только уникальные названия. Например:

GAZP
ROSN
VTB
GMKN

Решение: А вот как:
SELECT emitent FROM deal GROUP BY emitent HAVING count(*)!=0
Оказалось можно сделать проще: (спасибо, mvtm): 
SELECT DISTINCT emitent FROM deal
или
SELECT emitent FROM deal GROUP BY emitent

вторник, 12 октября 2010 г.

Простейшей cvs (с помощью архиватора и bat скрипта)

Предыстория:
     Начал писать я одну прогу, каждый день, заводя новый каталог для новой версии программы. Через несколько дней я понял, что каждый раз настраивать файлы и IDE под новый каталог, как то не спортивно... Решил, что было бы хорошо создавать архив каталога (где ведется разработка) и хранить его где-нибудь в другой папке.  При таком варианте я всегда смогу откатиться до предыдущей версии,  и  создавать архив в любое время ... Вообщем, реализация простейшей cvs....


Ну а дальше - понесЛось...

О скрипте:
     В скрипте я использую архиватор 7zip (http://www.7-zip.org/), т.к. он OpenSource и его родной формат 7z  гораздо эффективнее чем rar или zip. (Вообще не понимаю того кто еще устанавливает rar и главное зачем?)
Скрипт легко настроить под свою задачу, просто редактируем параметры, исходя из комментса...



@echo off
rem **************************************************
rem Эта строка вносит изменения в регистр.
rem Задает правильный формат времени, теперь если часы,
rem минуты или секунды будут представлены одной
rem цифрой, то автоматом добавится ноль в начале.
rem Раскомментировать если что...
rem **************************************************
rem C:\Windows\System32\REG ADD "HKCU\Control Panel\International" /v sTimeFormat /t REG_SZ /d "HH:mm:ss" /f 

rem **************************************************
rem Здесь форматируется дата и время
rem Этот кусок лучше не править...
rem **************************************************
set mydate=%date%
set mydate2=%mydate:~6,4%.%mydate:~3,2%.%mydate:~0,2%
set mytime=%time%
set mytime2=%mytime:~0,2%-%mytime:~3,2%

rem **************************************************
rem путь где лежит архиватор 7zip
rem если в пути присутствуют пробелы, необходимо брать 
rem такой кусок в кавычки
rem **************************************************
set PathTo7ZipProgram=C:\"Program Files"\7-Zip\7z.exe

rem **************************************************
rem Параметры архивироания
rem -a - Создаем архив, 
rem -r обход всех подкаталогов
rem -t7z тип архива, можно написть -tzip
rem -y на все вопросы отвечать yes
rem **************************************************
set Param=a -t7z -r -y

rem **************************************************
rem Папка откуда архивируем
rem **************************************************
set sourcePath="D:\C++ Progs\Market"

rem **************************************************
rem Папка куда архивируем
rem **************************************************
set distPath="D:\C++ Progs\Market\Arhive\"

rem **************************************************
rem Здесь формируем название нашего архива 
rem Например:2010.09.10_11-15_example.7z
rem **************************************************
set arhiveFileName=%mydate2%_%mytime2%_example.7z

rem **************************************************
rem в принципе можно еще пароль ставить автоматом...
rem см. справку по 7zip
rem **************************************************

echo ************************************************
echo *            Create and Save Arhive            *
echo *                                              *
echo *             Pingi-Pingi production           *
echo *        http://pingi-pingi.blogspot.com       *
echo ************************************************
echo * source DIR        :  %sourcePath%            
echo * distanation DIR   :  %distPath%
echo * arhive File Name  :  %arhiveFileName%
echo ****************** START ***********************

%PathTo7ZipProgram% %Param% %distPath%%arhiveFileName% %sourcePath%

echo ******************* END ************************

а если скрипт добавить в автозагрузку тогда еще полезнее будет ... правда только на время разработки конкретной аппликации :)

понедельник, 11 октября 2010 г.

Простое ведение лога на С++

В процессе отладки или работы приложения часто необходимо вести лог или выдавать отладочную информацию на экран или в файл.
Можно, конечно, воспользоваться сторонними библиотеками или написать собственный класс для этого. Однако, чтобы некоторые отладочные сообщения или конструкции не попали в "релизную" версию придется их отделять конструкциями типа:

#ifdef DEBUG
//Вывод отладочного сообщения в файл или на экран
#endif

Что может сильно захламить код...

Поэтому был написан следующий модуль лишенный таких недостатков:
#ifndef CALOG_H
#define CALOG_H
/******************************************************************************
* Здесь написаны макросы для выдачи отладочных сообщений на экран или файл
*
* PRINT1 (a) - Выдает сообщение (a) на экран.
* PRINT2 (a,b) - Выдает два сообщения (a) (b) на экран.
* PRINT3 (a,b,c) - Выдает три сообщения (a) (b) (с) на экран
* Аналогично для TOLOG - только сообщения идут в файл.
* Файл задается константой logFile1
*
* Макросы будут работать если определен DEBUG
* Если нет, то нет....
*
*
* Данная реализация уверенно работает под gcc 4.4.0 и С++0x.
* Для работы с "широкими" символами std::ofstream заменить на std::wofstream
* 
*
* А также можно определить:
*#define TIMETOLOG - пишет в лог время
*#define LINETOLOG - пишет в лог имя файла и номер строки
*
* Pingi-Pingi production
******************************************************************************/

#ifdef DEBUG

#ifndef LOGFILE
#define LOGFILE "Mylog.log"
#endif

#include <fstream>
#include <iostream>

#ifdef TIMETOLOG
#include <time.h>
#include <iomanip>
#endif

//Если выдаем имя файла и строку
#ifdef LINETOLOG
#define LINETO fwout <<"File:"<<__FILE__<<" Line:"<<__LINE__<<" | ";
#endif

//Если выдаем время
#ifdef TIMETOLOG
#define TIMETO \
        {\
            time_t rawtime;\
            struct tm *timeinfo;\
            time ( &rawtime );\
            timeinfo = localtime ( &rawtime );\
            fwout <<std::setw(2) << std::setfill ('0')\
                  <<timeinfo->tm_hour<<":"\
                  <<std::setw(2) << std::setfill ('0')\
                  <<timeinfo->tm_min<<":"\
                  <<std::setw(2) << std::setfill ('0')\
                  <<timeinfo->tm_sec<<" | ";\
        };
#endif


#ifndef LINETO
    #define LINETO
#endif
#ifndef TIMETO
    #define TIMETO
#endif


#define    PRINT1(a) \
    {\
       std::ostream &fwout=std::cout;\
       TIMETO\
       LINETO\
       fwout << (a) << std::endl;\
    };

#define    PRINT2(a,b) \
    {\
       std::ostream &fwout=std::cout;\
       TIMETO\
       LINETO\
       fwout << (a) << (b) << std::endl;\
    };

#define    PRINT3(a,b,c) \
    {\
       std::ostream &fwout=std::cout;\
       TIMETO\
       LINETO\
       fwout << (a) << (b) << (c) << std::endl;\
    };


#define    TOLOG1(a) \
   {\
     std::ofstream fwout (LOGFILE,std::ios_base::out|std::ios_base::app);\
     if(fwout.is_open())\
     {\
       TIMETO\
       LINETO\
       fwout << (a) << std::endl;\
       fwout.close();\
     }\
   };

#define    TOLOG2(a,b) \
   {\
     std::ofstream fwout (LOGFILE,std::ios_base::out|std::ios_base::app);\
     if(fwout.is_open())\
     {\
        TIMETO\
        LINETO\
        fwout << (a);\
        fwout << (b);\
        fwout <<std::endl;\
        fwout.close();\
     }\
   };

#define    TOLOG3(a,b,c) \
   {\
     std::ofstream fwout (LOGFILE,std::ios_base::out|std::ios_base::app);\
     if(fwout.is_open())\
     {\
        TIMETO\
        LINETO\
        fwout << (a) << (b) << (c) <<std::endl;\
        fwout.close();\
     }\
   };

#else

#define PRINT1(a)
#define PRINT2(a,b)
#define PRINT3(a,b,c)
#define TOLOG1(a)
#define TOLOG2(a,b)
#define TOLOG3(a,b,c)

#endif

#endif 

Если мы в своей программе определяем #DEBUG, то у нас работают ф-ии PRINT и TOLOG если же #DEBUG не определен, то вместо них в код будут подставлены аналогичные ф-ии пустышки.
И все...

Ниже пример использования данного модуля:

//Пример использования CALog.hpp
//pingi-pingi production
//http://pingi-pingi.blogspot.com/

#include <stdlib.h>

//Важно!
//Определяем параметры до #include "CALog.hpp"
#define DEBUG
#define LOGFILE "Mylog2.log"
#define TIMETOLOG

#include "CALog.hpp"

int main(int argc, char *argv[])
{
    //пишем в файл
    TOLOG1("Warrning...");
    TOLOG2("Parametr count = ", 5666.3444);

    //выдаем на экран (stdout)
    PRINT2("Problem Here, Number is = ",300);
    PRINT3("Problem Here:","Param = ",0);

    system("PAUSE");
    return EXIT_SUCCESS;
} 

Конечно такое решение не лишено проблем...
Например, хорошо бы сделать для этого модуля свое пространство имен. т.к. используемые в этом коде переменные  могут привести к конфликту с именованием переменных в основной программе. Однако оно работает и весьма успешно...

пятница, 8 октября 2010 г.

Использование базы данных на sqlite

Есть такой вариант облеченной базы mySQL.

Главное отличие от MySQL в отсутствии сервера, т.е. базу можно создавать и использовать локально - на том компе, где установлена прога.


Для создания БД можно использовать:
  • Командную строку (дополнительно качаем tools c сайта-проекта)
  • GUI интерфейс, бесплатный sqlite browser берем отсюда: http://sqlitebrowser.sourceforge.net/
  • Программно, пользуясь API (качаем source code c сайта-проекта)

Сайт проекта:
http://www.sqlite.org

По русски, описание и пример:
http://www.codenet.ru/db/other/sqlite/
http://www.samag.ru/cgi-bin/go.pl?q=articles;n=02.2004;a=04

Установка:
Скачиваем исходники, и далее подключаем библиотеки sqlite3 к своему проекту.

Пример номер 1
- Создание/открытие БД
- Создание таблицы
- Завершение работы с БД


#include <iostream> 
#include "sqlite3.h" 

using namespace std; 

int main(int argc, char **argv) 
{ 
    cout << "Hello world SQLite!" << endl; 
    char *db_name="test.sl3"; 
    sqlite3 *db; 
    char *zErrMsg = 0; 
    int error; 

    //Создание или открытие БД 
    error = sqlite3_open(db_name, &db); 
    if ( error ) 
    { 
        cout<<"Can't open database: "<<sqlite3_errmsg(db)<<endl; 
        sqlite3_close(db); 
    } 

    //Создание таблицы 
    error = sqlite3_exec(db, "CREATE TABLE table1 (id INTEGER PRIMARY KEY,field1 TEXT,field2 TEXT);", NULL, 0, &zErrMsg); 
    if ( error ) 
    { 
        cout<<"Can't create tables: "<<sqlite3_errmsg(db)<<endl; 
        sqlite3_close(db); 
    } 

    sqlite3_close(db); 

    return 0; 
} 

Пример номер 2


- Создание/открытие БД
- Создание таблицы
- Вставка данных
- Выборка из БД и отображение на экране результата
- Завершение работы с БД


#include <iostream>
#include "sqlite3.h"

using namespace std;

int main(int argc, char **argv)
{
    cout << "Hello world SQLite!" <<endl<<endl;
    char *db_name="test.sl3";
    sqlite3 *db;
    char *zErrMsg = 0;
    int error;

    //------------------------------
    //Создание или открытие БД
    //------------------------------
    error = sqlite3_open(db_name, &db);
    if ( error )
    {
        cout<<"Can't open database: "<<sqlite3_errmsg(db)<<endl;
        sqlite3_close(db);
    }

    //------------------------------
    //Создание таблицы
    //------------------------------
    //Если таблица уже создана, то эта конструкция будет выдавать ошибку!
    error = sqlite3_exec(db, "CREATE TABLE table1 (id INTEGER PRIMARY KEY,field1 TEXT,field2 TEXT);", NULL, 0, &zErrMsg);
    if ( error )
    {
        cout<<"Can't create table: "<<sqlite3_errmsg(db)<<endl;
        sqlite3_close(db);
    }

    //------------------------------
    //Ввод данных в таблицу
    //------------------------------
    error = sqlite3_exec(db, "INSERT INTO table1(field1, field2) VALUES ('Super', 'SQL');", NULL, 0, &zErrMsg);
    if ( error )
    {
        cout<<"Can't insert data to table: "<<sqlite3_errmsg(db)<<endl;
        sqlite3_close(db);
    }

    //------------------------------
    //Выборка данных из базы
    //------------------------------
    sqlite3_stmt    *res;
    const char      *tail;

    error = sqlite3_prepare_v2(db,"SELECT field1, field2,id from table1 order by id", 1000, &res, &tail);
    if ( error )
    {
        cout<<"Can't select data: "<<sqlite3_errmsg(db)<<endl;
        sqlite3_close(db);
    }
    //Отображаем на экране
    cout << "Display result from table1" << endl;
    int     rec_count = 0;
    while (sqlite3_step(res) == SQLITE_ROW)
    {
        cout<<"Row ("<<rec_count<<"):"<<sqlite3_column_text(res, 0)<<" ";
        cout<<sqlite3_column_text(res, 1)<<" ";
        cout<<sqlite3_column_text(res, 2)<<endl;

        rec_count++;
    }

    //------------------------------
    //Корректное завершение работы с БД
    //------------------------------
    sqlite3_close(db);
    return 0;
}  

среда, 6 октября 2010 г.

Прием почты с помощью сURL

В последней версии сURL появилась возможность работы с почтовыми протоколами POP3 и SMTP. Вот небольшой пример, как получить почту по протоколу POP3 с яндекса.

/***************************************************
Пример показывает как получить почту по протоколу  POP3
При запуске без параметров - выводит список номеров 
сообщений в почтовом ящике.
При передачи параметра (числа) в командной строке
программа - считает конкретное сообщение, за номером 
таким-то, из почтового ящика.

Автор: PINGI-PINGI
****************************************************/
#include <string>
#include <iostream>
#include <fstream>
#include "curl/curl.h"
using namespace std;

static char errorBuffer[CURL_ERROR_SIZE];
static string buffer;
// Call Back ф-ия. вызывается каждый раз при приеме данных
static int writer(char *data, size_t size, size_t nmemb, string *buffer)
{
    int res = 0;
    if (buffer != NULL)
    {
        buffer->append(data, size * nmemb);
        res = size * nmemb;
    }
    return res;
}

int main(int argc, char **argv)
{
    string filename = "result.txt";
    string link;
    string number_of_mail;    
    link = "pop3://YouLogin:YouPassword@pop.yandex.ru";
    if (argc == 2)
    {
       number_of_mail.assign (argv[1]);       
       link += "/";
       link += number_of_mail;
    }        
    CURL *curl;
    CURLcode result;    
    curl = curl_easy_init();    
    if (curl)
    {       
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        
        //Задем опции
        curl_easy_setopt(curl, CURLOPT_URL, link.c_str()); 
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
        //Выполняем...
        result = curl_easy_perform(curl);        
        if (result == CURLE_OK)
        {
            std::ofstream out_file (filename.c_str());
            if (out_file.is_open())
            {
                cout << "Write Data to "<< filename << endl;
                out_file << buffer;
            }
            out_file.close ();
        }
        else
            cout << "Error! " << errorBuffer << endl;

    }
    curl_easy_cleanup(curl);
    return 0;
}

вторник, 5 октября 2010 г.

Скрипт проверки доступности хоста методом ping в Win и Linux

Бывают задачи для которых важно определить доступность сетевого ресурса:

Например, если удаленный компьютер доступен, то подключить его сетевой диск.
Или например, при сбое в сети переключится на другого интернет провайдера и т.п.

Для решения подобных задач я использую скрипт (основанный на команде ping), который умеет проверять доступность сетевого ресурса.

Для Windows:

@echo off

ping -n 1 www.yandex.ru > %TEMP%\pinglog

find "Unknown host" < %TEMP%\pinglog > nul
if not errorlevel 1 echo Unknown host && goto :eof

find "Reply from" < %TEMP%\pinglog > nul
if not errorlevel 1 echo Ok && goto :eof

find "Request timed out" < %TEMP%\pinglog > nul
if not errorlevel 1 echo Time out && goto :eof


Для Linux:

#!/bin/bash

ADDRESS="www.yandex.ru"

if ping -c 1 -s 1 -W 1 $ADDRESS
then
    echo "Connection Good "
else
    echo "Connection Lost "
fi

Работа с протоколами FTP, HTTP, HTTPS, SCP, TELNET, SMTP, POP3 и т.п. - с помощью библиотеки cURL

Бывает задача, что надо скачать "что-то" из сети программным способом,  по протоколу FTP или HTTP, или получить почту, или сделать "что-то" через telnet...
Можно конечно попытать "счастья" в программировании сокетов, однако это прямой путь к изобретению велосипеда. Если же еще и делать такую программу кроссплатформенной, то времени на разработку основной задачи может и не остаться...

Чтобы не изобретать велосипедов, можно использовать библиотеку cURL . Эта библиотека умеет работать на платформах Win и Linux. Умеет работать с протоколами: DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET и TFTP. В последней версии (7.21.1) есть возможность работы с почтовыми протоколами SMTP и POP. Кроме того, умеет работать через прокси сервер.

Далее я расскажу как установить эту библиотеку:

В  Linux:
Качаем с официального сайта http://curl.haxx.se/ необходимый архив с исходниками.
Распаковываем и далее, стандартыми командами, (./configure make install) устанавливаем.
На этом установка завершена.


Для  Win:
Все просто, скачиваем libcurl, распаковываем в какую-нибудь директорию.

У меня например все сторонние библиотеки располагаются в одной директории, вот так:
C:\C++ Libs\
    \curl-7.21.1
    \zlib_1_2_5
    ...
Что считаю удобным т.к.все собрано в одном месте да и потом прописывать пути в разных прогах проще.

После всех манипуляций запускаем IDE, я например использую CodeBlock, поэтому далее рассказываю на основе этой IDE.
Создаем проект. (например - консоле апликацию)
Далее, подключаем библиотеку cURL к нашему проекту.
Идем в Menu->Project-Build Options и прописываем пути к библиотекам.

Очень Важно! Соблюдаем именно такой порядок следования:
libcurl.a
libwsock32.a (из пакета minGW)
libwldap32.a (из пакета minGW)

libz.a - библиотеку zlib я добавляю отдельно, хотя она есть и в варианте поставки curl. Можно использовать и так, и так.

Приведенный выше список библиотек является минимальным для работы cURL.

В свой проект я добавил дополнительные библиотеки из поставки cURL:

В разделе #define нужно задать: CURL_STATICLIB
Например так: 


Небольшой пример скачивания веб страницы:

#include <string>
#include <iostream>
#include "curl/curl.h"
using namespace std;

//буфер, для хранения  ошибки
static char errorBuffer[CURL_ERROR_SIZE]; 
//Скаченные данные
static string buffer; 

//Эта ф-ия вызывется при получении данных
static int writer(char *data, size_t size, size_t nmemb, string *buffer)
{
  int res = 0;
  if (buffer != NULL)
  {
    buffer->append(data, size * nmemb);    
    res = size * nmemb;
  }  
  return res;
}

int main(void)
{    
    CURL *curl;
    CURLcode result;    
    curl = curl_easy_init();    
    if (curl)
    {
      //Установка опций    
      curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
      curl_easy_setopt(curl, CURLOPT_URL, "www.ya.ru");
      curl_easy_setopt(curl, CURLOPT_HEADER, 1);      
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);      
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
      //Запуск на выполнение
      result = curl_easy_perform(curl);      
      if (result == CURLE_OK)      
        cout << buffer << "\n";
      else        
        cout << "Error :" << errorBuffer << endl;
  }  
  curl_easy_cleanup(curl);
  return 0;
}

На этом пока все, в следующей статье напишу как работать с почтой через cURL.



Полезные ссылки: 
http://ru.wikipedia.org/wiki/CURL 
http://www.xakep.ru/magazine/xa/121/092/1.asp 
http://pblog.ru/?p=607#more-607

понедельник, 4 октября 2010 г.

Установка и работа с MySQL на С++ (MVS,MinGV,Borland)

Установка MySQL 
  1. Качаем последнию версию MySQL Communication Server с сайта: http://www.mysql.com/ 
  2. Качаем MySQL GUI Tools Downloads для работы с БД через GUI. ( При установке MySQL выбираем расширенную установку и ставим галочки в нужном месте, для включения include и lib. )
  3. Ставим GUI Tools
  4. Проверяем что база работает, запустив GUI и сделав коннект к базе. 
  5. Проверяем что созданы директории include и lib в папке куда установлен MySQL
Настройка Microsoft Visual Studio
  1. Необходимо прописать пути к директориям include и lib (Tools->Options->Projects and Solution->VC++ Directories) 
  2. В опциях самого проекта-программы (Project->$Name Property->Configuration Properties->Linker->General) в поле Additional Library Directories прописываем путь к директории lib.
  3. Почти там же (Project->$Name Property->Configuration Properties->Linker->Input) в поле Additional Dependencies пишем libmysql.lib
Все можно запускать пример.

Настройка minGW  Dev++


  1. Вообщем почти также прописываем пути к include и lib в оболочке Dev++ (Параметры компилятора->Директории)
  2. Прописывем библиотеку libmysql.lib в параметрах проекта в разделе параметры->компоновщик.
  3. И если происходит ошибка: "SOCKET чего там не определен", то: Открываем mysql.h и ищем там строку #define my_socket SOCKET и правим так: 
#ifdef __WIN__   
#include <windows.h>
#define my_socket UINT_PTR
//#define my_socket SOCKET 
#else 



windows.h здесь добавился чтобы определился UINT_PTR 


Для Borland (сам не устанавливал, однако, пришлось вникать теоретически)
Вообщем аналогичные действия, однако, добавлется еще один момент.

Т.к. формат lib-ов в borland используется другой (а libmysql.lib сделан изначально под VC)
необходимо сделать libmysql.lib самомтоятельно, имея libmysql.dll и две утилиты из поставки борланда impdef.exe, implib.exe.
Технология должна быть примерно такой:
 
  1. С помощью impdef.exe вытаскиваем из dll - файл с описанием всех ф-ий, например что-то.def.  
  2. Возможно придется поэкперементировать с редактированием файла: что-то.def  (например с добавлением к именам ф-ий '_' или написания строк типа _функция@4=функция, другие варианты написания этого файла есть в инэнте.
  3. С помошью implib.exe и на основе что-то.def генерируем libmysql.lib
Вроде всё. Вероятно будет работать.

Теперь напишем пример на С++:


/* 
  Name:  
  Copyright:  
  Author:Pingi-Pingi  
  Date: 
  Description:  
  This Exemple show: connect, select data, and close  MySQL DataBase. 
  File mysql.h has been changed for normal compilation (Please see comments in  
  mySQL.h from Pingi-Pingi) 
*/ 


#include <cstdlib> 
#include <iostream> 

#include "mysql.h" 

//using namespace std; 
MYSQL mysql; 
MYSQL_ROW row; 
MYSQL_RES *res; 

int main(int argc, char *argv[]) 
{ 
     
    std::cout<<"Start"<<std::endl; 

   MYSQL* mysql = mysql_init((MYSQL*) 0);  
   mysql->free_me = 1;  
   mysql->reconnect = 1;  
   std::cout<<"Connect..."<<std::endl; 
   if (!mysql_real_connect( mysql, "localhost","login","password",NULL, 3306, NULL, 0 )) 
   { 
      std::cout<<"Error code:"<<mysql_errno(mysql)<<" Error:"<<mysql_error(mysql)<<std::endl; 
      mysql_close(mysql); 
      return 0; 
   }    
   std::cout<<"Connected to Data Base!"<<std::endl;  
    
   //Execute Query 
   char *myqery="SELECT * FROM test.table"; 
   if (mysql_query(mysql, myqery))  
   { 
      std::cout<<myqery<<std::endl; 
      std::cout<<"Error code:"<<mysql_errno(mysql)<<" Error:"<<mysql_error(mysql)<<std::endl;       
      mysql_close(mysql) ; 
      return 0; 
   }          


      MYSQL_RES* presults = mysql_store_result(mysql);       
      if (presults) //???? ???? ?????? ? ??????? 
      {                
         MYSQL_ROW row; 
             
         while ((row=mysql_fetch_row(presults))) 
         {                
            std::cout<<row[0]<<","<<row[1]<<","<<row[2]<<std::endl;                
         }  
      } 

    
   mysql_close(mysql) ; 
     
    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 


Этот код реализует простые операции с БД, такие как:
connect, select data, and close.

Ниже, несколько расширенный пример, который умеет:
Открыть, Считать данные, Записать, Обновить, Закрыть БД

/*
  Name: 
  Copyright: 
  Author:Pingi-Pingi
  Date: 
  Description: 
  This Exemple show: connect, select data, and close  MySQL DataBase.
  File mysql.h has been changed for normal compilation (Please see      comments in   mySQL.h)
*/

#include <cstdlib>
#include <iostream>
#include "mysql.h"
//using namespace std;

MYSQL mysql;
MYSQL_ROW row;
MYSQL_RES *res;

int main(int argc, char *argv[])
{
    std::cout<<"Start"<<std::endl;

  //Коннектимся к БД

   MYSQL* mysql = mysql_init((MYSQL*) 0); 
   mysql->free_me = 1; 
   mysql->reconnect = 1; 
   std::cout<<"Connect..."<<std::endl;

   if (!mysql_real_connect( mysql, "localhost","myName","myPass",NULL, 3306, NULL, 0 ))
   {
      std::cout<<"Error code:"<<mysql_errno(mysql)<<" Error:"<<mysql_error(mysql)<<std::endl;
      mysql_close(mysql);
      return 0;
   }   
   std::cout<<"Connected to Data Base!"<<std::endl; 
   //Чтение из БД

   std::cout<<"Read From DB..."<<std::endl;
   //Read From BD

   char *myqery="SELECT * FROM test.table";
   if (mysql_query(mysql, myqery)) 
   {
      std::cout<<myqery<<std::endl;
      std::cout<<"Error code:"<<mysql_errno(mysql)<<"Error:"<<mysql_error(mysql)<<std::endl;
      mysql_close(mysql);
      return 0;
   }         

   //Выдаем все что получили на экран
   MYSQL_RES* presults = mysql_store_result(mysql);      
   if (presults) 
   {               
      MYSQL_ROW row;
      while ((row=mysql_fetch_row(presults)))
      {               
          std::cout<<row[0]<<","<<row[1]<<","<<row[2]<<std::endl;               
      } 
   }      
   mysql_free_result(presults); /* освободили */   
   std::cout<<"Read From DB...Done"<<std::endl;    //Вставка в таблицу строки
   std::cout<<"Insert to DB..."<<std::endl;

   char *myqery_insert="INSERT INTO test.table(code,description) VALUES ('122345','This Description')";
   if (mysql_query(mysql, myqery_insert)) 
   {
      std::cout<<myqery<<std::endl;
      std::cout<<"Error code:"<<mysql_errno(mysql)<<"Error:"<<mysql_error(mysql)<<std::endl;      
      mysql_close(mysql);
      return 0;
   }            
   std::cout<<"Insert to DB...Done"<<std::endl;   //Обновление полей
   std::cout<<"Update DB..."<<std::endl;
    
   char *myqery_update="UPDATE test.table SET code='5555', description='This Update Description' where id='3'";
   if (mysql_query(mysql, myqery_update)) 
   {
      std::cout<<myqery<<std::endl;
      std::cout<<"Error code:"<<mysql_errno(mysql)<<"Error:"<<mysql_error(mysql)<<std::endl;
      mysql_close(mysql);
      return 0;
   }   
   std::cout<<"Update DB...Done"<<std::endl;         

   mysql_close(mysql);
   system("PAUSE");
   return EXIT_SUCCESS;
}