Logo Search packages:      
Sourcecode: qnapi version File versions  Download package

qnapiprojektengine.cpp

/*****************************************************************************
** QNapi
** Copyright (C) 2008 Krzemin <pkrzemin@o2.pl>
**
** 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 file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
*****************************************************************************/

#include "qnapiprojektengine.h"

// konstruktor klasy
QNapiProjektEngine::QNapiProjektEngine(const QString & movieFile, const QString & subtitlesFile)
      : QNapiAbstractEngine(movieFile, subtitlesFile)
{
      p7zipPath = GlobalConfig().p7zipPath();
      lang = GlobalConfig().language();
      nick = GlobalConfig().nick();
      pass = GlobalConfig().pass();
      noBackup = GlobalConfig().noBackup();
      tmpFile =  tmpPath + "/QNapi.napisy.7z";
}

// destruktor klasy
QNapiProjektEngine::~QNapiProjektEngine()
{
      cleanup();
}

// oblicza sume kontrolna dla pliku filmowego (md5 z pierwszych 10MB pliku)
QString QNapiProjektEngine::checksum(const QString & filename, bool limit10M)
{
      QFile file(filename);
      QByteArray fileArray;

      if(!file.open(QIODevice::ReadOnly))
            return QString("");

      fileArray = limit10M ? file.read(NAPI_10MB) : file.readAll();
      file.close();

      QByteArray b = QCryptographicHash::hash(fileArray, QCryptographicHash::Md5);
      fileArray.clear();

      QString out;
      char next[3];

      for(int i = 0; i < 16; i++)
      {
            snprintf(next, 3, "%.2x", (unsigned char)b[i]);
            out += next;
      }
      
      checkSum = out;
      return checkSum;
}

QString QNapiProjektEngine::checksum()
{
      return checksum(moviePath);
}

// Probuje pobrac napisy do filmu z serwera NAPI
bool QNapiProjektEngine::tryDownload()
{
      if(checkSum.isEmpty()) checksum();
      
      SyncHTTP http;
      QString urlTxt = napiDownloadUrlTpl.arg(lang).arg(checkSum).arg(napiFDigest(checkSum)).arg(nick).arg(pass);

      QUrl url(urlTxt);

      http.setHost(url.host());
      http.syncGet(url.path() + "?" + url.encodedQuery());

      QByteArray buffer = http.readAll();

      if(buffer.indexOf("NPc") == 0)
            return false;

      QFile file(tmpFile);
      if(file.exists()) file.remove();
      if(!file.open(QIODevice::WriteOnly))
            return false;

      int r = file.write(buffer);
      file.close();
      return (bool)r;
}

// Probuje dopasowac napisy do filmu
bool QNapiProjektEngine::tryMatch()
{
      if(!QFile::exists(tmpFile)) return false;
      if(!QFile::exists(moviePath)) return false;
      if(!checkP7ZipPath()) return false;

      QStringList args;
      args << "x" << "-y" << ("-p" + napiZipPassword) << ("-o" + tmpPath) << tmpFile;

      QProcess p7zip;
      p7zip.start(p7zipPath, args);

      if(!p7zip.waitForFinished()) return false;

      QString subtitleFile = tmpPath + "/" + checkSum + ".txt";
      if(!QFile::exists(subtitleFile)) return false;

      QFileInfo mf(moviePath);

      QString newName = mf.path() + "/" + mf.completeBaseName() + ".txt";

      if(QFile::exists(newName))
      {
            if(!noBackup)
            {
                  QFileInfo nn(newName);
                  QFile::copy(newName, nn.path() + "/" + nn.completeBaseName() + "_kopia.txt");
            }
            QFile::remove(newName);
      }

      bool r;

#ifdef Q_WS_WIN
      // Pod windowsem, aby "wyczyscic" atrybuty pliku, tworzymy go na nowo
      QFile f(newName), f2(subtitleFile);
      if(!f.open(QIODevice::WriteOnly) || !f2.open(QIODevice::ReadOnly))
      {
            r = false;
            f.close();
      }
      else
      {
            r = f.write(f2.readAll()) > 0;
            f2.close();
            f.close();
      }
#else
      // pod normalnymi OS-ami nie trzeba sie gimnastykowac z atrybutami
      r = QFile::copy(subtitleFile, newName);
#endif

      subtitlesPath = newName;

      QFile::remove(subtitleFile);
      QFile::remove(tmpFile);

      return r;
}

void QNapiProjektEngine::cleanup()
{
      QFile::remove(tmpFile);
}

// Tworzy konto uzytkownika na serwerze NAPI
bool QNapiProjektEngine::createUser(const QString & nick, const QString & pass,
                                                      const QString & email, QString * response)
{
      QMultipartHttpRequest postData;

      postData.addBoundary();
      postData.addContentDisposition("name=\"login\"");
      postData.addData(nick);

      postData.addBoundary();
      postData.addContentDisposition("name=\"haslo\"");
      postData.addData(pass);

      postData.addBoundary();
      postData.addContentDisposition("name=\"mail\"");
      postData.addData(email);

      postData.addBoundary();
      postData.addContentDisposition("name=\"z_programu\"");
      postData.addData(QString("true"));

      postData.addEndingBoundary();

      QByteArray data = postData.requestStream();

      QUrl url(napiCreateUserUrlTpl);

      QHttpRequestHeader header("POST", url.path());

      header.setValue("Host", url.host());
      header.setValue("Accept", "text/html, */*");
      header.setValue("Content-Type", "multipart/form-data; boundary=" + postData.boundaryTxt());
      header.setValue("Connection", "keep-alive");
      header.setValue("User-Agent", QString("QNapi ") + QNAPI_VERSION);

      SyncHTTP http;
      http.setHost(url.host());
      if(!http.syncRequest(header, data))
            return false;

      *response = QTextCodec::codecForName("windows-1250")->toUnicode(http.readAll());

      return true;
}

// Sprawdza uzytkownika w bazie
bool QNapiProjektEngine::checkUser(const QString & nick, const QString & pass)
{
      SyncHTTP http;
      QString urlTxt = napiCheckUserUrlTpl.arg(nick).arg(pass);

      QUrl url(urlTxt);
      http.setHost(url.host());
      http.syncGet(url.path() + "?" + url.encodedQuery());

      QString buffer = http.readAll();
      if(buffer.indexOf("ok") == 0) return true;
      return false;
}

// Wrzuca napisy do bazy NAPI
QNapiProjektEngine::UploadResult
      QNapiProjektEngine::uploadSubtitles(const QString & language, const QString & nick,
                                                            const QString & pass, bool correct, const QString & comment)
{
      if(!QFile::exists(moviePath) || !QFile::exists(subtitlesPath))
            return NAPI_FAIL;

      MovieInfo movieInfo(moviePath);

      unsigned long movie_size = QFileInfo(moviePath).size();
      QString movie_md5 = checksum(moviePath);
      QString subtitles_md5 = checksum(subtitlesPath, false);

      QString newSubtitlesName = tmpPath + "/" + movie_md5 + ".txt";
      if(QFile::exists(newSubtitlesName)) QFile::remove(newSubtitlesName);
      if(!QFile::copy(subtitlesPath, newSubtitlesName))
            return NAPI_FAIL;

      QString zipFileName = QFileInfo(newSubtitlesName).path() + "/"
                                          + QFileInfo(newSubtitlesName).completeBaseName() + ".zip";

      if(QFile::exists(zipFileName))
            QFile::remove(zipFileName);

      QStringList args;
      args << "a" << "-t7z" << "-bd" << "-y";
#ifndef Q_WS_WIN
      args << "-l";
#endif
      args << zipFileName << (QString("-p")+napiZipPassword) << newSubtitlesName;

      QProcess p7zip;
      p7zip.start(p7zipPath, args);

      if(!p7zip.waitForFinished())
            return NAPI_FAIL;

      QFile::remove(newSubtitlesName);

      if(!QFile::exists(zipFileName))
            return NAPI_FAIL;

      // Przygotowujemy dane do zapytania POST
      QMultipartHttpRequest postData;

      postData.addBoundary();
      postData.addContentDisposition("name=\"kmt\"");
      postData.addData(comment);

      postData.addBoundary();
      postData.addContentDisposition("name=\"poprawka\"");
      postData.addData(QString(correct ? "true" : "false"));

      postData.addBoundary();
      postData.addContentDisposition("name=\"v\"");
      postData.addData(QString("other"));

      postData.addBoundary();
      postData.addContentDisposition("name=\"l\"");
      postData.addData(language);

      postData.addBoundary();
      postData.addContentDisposition("name=\"t\"");
      postData.addData(napiFDigest(movie_md5));

      postData.addBoundary();
      postData.addContentDisposition("name=\"m_filename\"");
      postData.addData(QFileInfo(moviePath).fileName());

      postData.addBoundary();
      postData.addContentDisposition("name=\"nick\"");
      postData.addData(nick);

      postData.addBoundary();
      postData.addContentDisposition("name=\"pass\"");
      postData.addData(pass);

      postData.addBoundary();
      postData.addContentDisposition("name=\"s_hash\"");
      postData.addData(subtitles_md5);

      postData.addBoundary();
      postData.addContentDisposition("name=\"MAX_FILE_SIZE\"");
      postData.addData(QString("512000"));

      postData.addBoundary();
      postData.addContentDisposition("name=\"plik\"; filename=\"" +
            QFileInfo(zipFileName).fileName() + "\"");
      postData.addContentType("subtitles/zip");

      QFile fZip(zipFileName);
      if(!fZip.open(QIODevice::ReadOnly))
            return NAPI_FAIL;

      postData.addData(fZip.readAll());
      postData.addEndingBoundary();

      fZip.close();
      QFile::remove(zipFileName);

      QByteArray data = postData.requestStream();

      QString movie_fps = QString::number((int)ceil(movieInfo.fps * 100));
      movie_fps.insert(2, ',');

      QString urlTxt;
      
      if(movieInfo.isErr)
      {
            urlTxt = napiUploadUrlSimpleTpl.arg(movie_md5).arg(movie_size);
      }
      else
      {
            urlTxt = napiUploadUrlTpl.arg(movieInfo.time).arg(movieInfo.width)
                                                      .arg(movieInfo.height).arg(movie_fps)
                                                      .arg(movie_md5).arg(movie_size);
      }

      QUrl url(urlTxt);

      QHttpRequestHeader header("POST", url.path() + "?" + url.encodedQuery());

      header.setValue("Host", url.host());
      header.setValue("Accept", "text/html, */*");
      header.setValue("Content-Type", "multipart/form-data; boundary=" + postData.boundaryTxt());
      header.setValue("Connection", "keep-alive");
      header.setValue("User-Agent", QString("QNapi ") + QNAPI_VERSION);

      SyncHTTP http;
      http.setHost(url.host());
      if(!http.syncRequest(header, data))
            return NAPI_FAIL;

      QString response = http.readAll();

      if(response.indexOf("NPc0") == 0)
            return NAPI_ADDED_NEW;
      if((response.indexOf("NPc2") == 0) || (response.indexOf("NPc3") == 0))
            return NAPI_OK;
      return NAPI_UNKNOWN;
}

// Wysyla blad o niepasujacyh napisach
QNapiProjektEngine::ReportResult
      QNapiProjektEngine::reportBad(const QString & language, const QString & nick, const QString & pass,
                                                      const QString & comment, QString *response)
{
      QFileInfo fi(moviePath);
      subtitlesPath = fi.path() + "/" + fi.completeBaseName() + ".txt";

      if(!QFile::exists(subtitlesPath))
            return NAPI_NO_SUBTITLES;

      checksum();

      QMultipartHttpRequest postData;

      postData.addBoundary();
      postData.addContentDisposition("name=\"nick\"");
      postData.addData(nick);

      postData.addBoundary();
      postData.addContentDisposition("name=\"pass\"");
      postData.addData(pass);

      postData.addBoundary();
      postData.addContentDisposition("name=\"l\"");
      postData.addData(language);

      postData.addBoundary();
      postData.addContentDisposition("name=\"md5\"");
      postData.addData(checkSum);

      postData.addBoundary();
      postData.addContentDisposition("name=\"kmt\"");
      postData.addData(comment);
      postData.addEndingBoundary();

      QByteArray data = postData.requestStream();

      QUrl url(napiReportBadUrlTpl);

      QHttpRequestHeader header("POST", url.path());

      header.setValue("Host", url.host());
      header.setValue("Accept", "text/html, */*");
      header.setValue("Content-Type", "multipart/form-data; boundary=" + postData.boundaryTxt());
      header.setValue("Connection", "keep-alive");
      header.setValue("User-Agent", QString("QNapi ") + QNAPI_VERSION);

      SyncHTTP http;
      http.setHost(url.host());
      if(!http.syncRequest(header, data))
            return NAPI_NOT_REPORTED;

      *response = QTextCodec::codecForName("windows-1250")->toUnicode(http.readAll());

      return NAPI_REPORTED;
}

// Tajemnicza funkcja f() :D
QString QNapiProjektEngine::napiFDigest(const QString & input)
{
      if(input.size() != 32) return "";

      int idx[] = {0xe, 0x3, 0x6, 0x8, 0x2},
            mul[] = {2, 2, 5, 4, 3},
            add[] = {0x0, 0xd, 0x10, 0xb, 0x5},
            a, m, i, t, v;

      QString b;
      char tmp[2] = { 0, 0 };

      for(int j = 0; j <= 4; j++)
      {
            a = add[j];
            m = mul[j];
            i = idx[j];

            tmp[0] = input[i].toAscii();
            t = a + (int)(strtol(tmp, NULL, 16));
            v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));

            snprintf(tmp, 2, "%x", (v * m) % 0x10);
            b += tmp;
      }

      return b;
}

Generated by  Doxygen 1.6.0   Back to index