1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00
This commit is contained in:
Сухарик 2014-11-14 21:20:11 +03:00
commit 93396160f7
48 changed files with 1335 additions and 239 deletions

View File

@ -1,20 +1,20 @@
qTox
======
Powerful Tox client that tries to follow the Tox UI mockup while running on all major systems. <br/>
This GUI uses code from @nurupo'tos ProjectTox-Qt-GUI, in particular the "Core" Toxcore wrapper. <br/>
However, it is not a fork.
qTox is a powerful Tox client that tries to follow the Tox design guidelines while running on all major platforms. <br/>
<h2>Features</h2>
- One to one chat with friends
- Group chats
- File transfers, with previewing of images
- Audio calls
- Audio calls, including group calls
- Video calls
- Tox DNS
- Tox DNS and Tox URI support
- Translations in various languages
- Avatars
- Auto-updates on Windows and Mac, packages on Linux
- And many more options!
<h2>Downloads</h2>
@ -33,3 +33,9 @@ This client runs on Windows, Linux and Mac natively.<br/>
##Documentation:
[Compiling](/INSTALL.md)
##Developer overview:
[GitStats](http://207.12.89.155/index.html)<br/>
[Mac & Linux jenkins](https://jenkins.libtoxcore.so/user/tux3/my-views/view/qTox/)<br/>
[Windows jenkins](http://207.12.89.155:8080)<br/>

View File

@ -33,7 +33,8 @@ FORMS += \
src/widget/form/settings/privacysettings.ui \
src/widget/form/loadhistorydialog.ui \
src/widget/form/inputpassworddialog.ui \
src/widget/form/setpassworddialog.ui
src/widget/form/setpassworddialog.ui \
src/widget/form/settings/advancedsettings.ui
CONFIG += c++11
@ -46,6 +47,10 @@ RESOURCES += res.qrc
GIT_VERSION = $$system(git rev-parse HEAD 2> /dev/null || echo "built without git")
DEFINES += GIT_VERSION=\"\\\"$$quote($$GIT_VERSION)\\\"\"
# date works on linux/mac, but it would hangs qmake on windows
# This hack returns 0 on batch (windows), but executes "date +%s" or return 0 if it fails on bash (linux/mac)
TIMESTAMP = $$system($1 2>null||echo 0||a;rm null;date +%s||echo 0) # I'm so sorry
DEFINES += TIMESTAMP=$$TIMESTAMP
DEFINES += LOG_TO_FILE
contains(JENKINS,YES) {
@ -148,7 +153,8 @@ HEADERS += src/widget/form/addfriendform.h \
src/toxdns.h \
src/widget/toxsave.h \
src/autoupdate.h \
src/misc/serialize.h
src/misc/serialize.h \
src/widget/form/settings/advancedform.h
SOURCES += \
src/widget/form/addfriendform.cpp \
@ -213,4 +219,5 @@ SOURCES += \
src/ipc.cpp \
src/widget/toxsave.cpp \
src/autoupdate.cpp \
src/misc/serialize.cpp
src/misc/serialize.cpp \
src/widget/form/settings/advancedform.cpp

154
res/gplv3.rtf Normal file
View File

@ -0,0 +1,154 @@
{\rtf1\ansi\deff0\adeflang1025
{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset0 Times New Roman;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\fnil\fprq2\fcharset0 Arial Unicode MS;}{\f4\fnil\fprq2\fcharset0 MS Mincho;}{\f5\fnil\fprq2\fcharset0 Tahoma;}{\f6\fnil\fprq0\fcharset0 Tahoma;}}
{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035\snext1 Normal;}
{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang255\ltrch\dbch\af4\langfe255\hich\f2\fs28\lang1035\loch\f2\fs28\lang1035\sbasedon1\snext3 Heading;}
{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035\sbasedon1\snext3 Body Text;}
{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035\sbasedon3\snext4 List;}
{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ai\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\i\loch\f0\fs24\lang1035\i\sbasedon1\snext5 caption;}
{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035\sbasedon1\snext6 Index;}
}
{\info{\author Kimmo Varis}{\creatim\yr2010\mo1\dy17\hr1\min15}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment StarWriter}{\vern3100}}\deftab709
{\*\pgdsctbl
{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}}
\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1035\i0\b0 GNU GENERAL PUBLIC LICENSE\line Version 3, 29 June 2007\line \line Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\line Everyone is permitted to copy and distribute verbatim copies\line of this license document, but
changing it is not allowed.\line \line Preamble\line \line The GNU General Public License is a free, copyleft license for\line software and other kinds of works.\line \line The licenses for most software and other practical works are designed\line to take away yo
ur freedom to share and change the works. By contrast,\line the GNU General Public License is intended to guarantee your freedom to\line share and change all versions of a program--to make sure it remains free\line software for all its users. We, the Free Software Foun
dation, use the\line GNU General Public License for most of our software; it applies also to\line any other work released this way by its authors. You can apply it to\line your programs, too.\line \line When we speak of free software, we are referring to freedom, not\line price. Ou
r General Public Licenses are designed to make sure that you\line have the freedom to distribute copies of free software (and charge for\line them if you wish), that you receive source code or can get it if you\line want it, that you can change the software or use pieces
of it in new\line free programs, and that you know you can do these things.\line \line To protect your rights, we need to prevent others from denying you\line these rights or asking you to surrender the rights. Therefore, you have\line certain responsibilities if you distribut
e copies of the software, or if\line you modify it: responsibilities to respect the freedom of others.\line \line For example, if you distribute copies of such a program, whether\line gratis or for a fee, you must pass on to the recipients the same\line freedoms that you receive
d. You must make sure that they, too, receive\line or can get the source code. And you must show them these terms so they\line know their rights.\line \line Developers that use the GNU GPL protect your rights with two steps:\line (1) assert copyright on the software, and (2) o
ffer you this License\line giving you legal permission to copy, distribute and/or modify it.\line \line For the developers' and authors' protection, the GPL clearly explains\line that there is no warranty for this free software. For both users' and\line authors' sake, the GPL r
equires that modified versions be marked as\line changed, so that their problems will not be attributed erroneously to\line authors of previous versions.\line \line Some devices are designed to deny users access to install or run\line modified versions of the software inside the
m, although the manufacturer\line can do so. This is fundamentally incompatible with the aim of\line protecting users' freedom to change the software. The systematic\line pattern of such abuse occurs in the area of products for individuals to\line use, which is precisely wh
ere it is most unacceptable. Therefore, we\line have designed this version of the GPL to prohibit the practice for those\line products. If such problems arise substantially in other domains, we\line stand ready to extend this provision to those domains in future versio
ns\line of the GPL, as needed to protect the freedom of users.\line \line Finally, every program is threatened constantly by software patents.\line States should not allow patents to restrict development and use of\line software on general-purpose computers, but in those that do
, we wish to\line avoid the special danger that patents applied to a free program could\line make it effectively proprietary. To prevent this, the GPL assures that\line patents cannot be used to render the program non-free.\line \line The precise terms and conditions for copyin
g, distribution and\line modification follow.\line \line TERMS AND CONDITIONS\line \line 0. Definitions.\line \line "This License" refers to version 3 of the GNU General Public License.\line \line "Copyright" also means copyright-like laws that apply to other kinds of\line wor
ks, such as semiconductor masks.\line \line "The Program" refers to any copyrightable work licensed under this\line License. Each licensee is addressed as "you". "Licensees" and\line "recipients" may be individuals or organizations.\line \line To "modify" a work means to copy fro
m or adapt all or part of the work\line in a fashion requiring copyright permission, other than the making of an\line exact copy. The resulting work is called a "modified version" of the\line earlier work or a work "based on" the earlier work.\line \line A "covered work" means
either the unmodified Program or a work based\line on the Program.\line \line To "propagate" a work means to do anything with it that, without\line permission, would make you directly or secondarily liable for\line infringement under applicable copyright law, except executing it
on a\line computer or modifying a private copy. Propagation includes copying,\line distribution (with or without modification), making available to the\line public, and in some countries other activities as well.\line \line To "convey" a work means any kind of propagation that
enables other\line parties to make or receive copies. Mere interaction with a user through\line a computer network, with no transfer of a copy, is not conveying.\line \line An interactive user interface displays "Appropriate Legal Notices"\line to the extent that it includes a
convenient and prominently visible\line feature that (1) displays an appropriate copyright notice, and (2)\line tells the user that there is no warranty for the work (except to the\line extent that warranties are provided), that licensees may convey the\line work under this
License, and how to view a copy of this License. If\line the interface presents a list of user commands or options, such as a\line menu, a prominent item in the list meets this criterion.\line \line 1. Source Code.\line \line The "source code" for a work means the preferred form o
f the work\line for making modifications to it. "Object code" means any non-source\line form of a work.\line \line A "Standard Interface" means an interface that either is an official\line standard defined by a recognized standards body, or, in the case of\line interfaces specified
for a particular programming language, one that\line is widely used among developers working in that language.\line \line The "System Libraries" of an executable work include anything, other\line than the work as a whole, that (a) is included in the normal form of\line packaging
a Major Component, but which is not part of that Major\line Component, and (b) serves only to enable use of the work with that\line Major Component, or to implement a Standard Interface for which an\line implementation is available to the public in source code form. A\line
"Major Component", in this context, means a major essential component\line (kernel, window system, and so on) of the specific operating system\line (if any) on which the executable work runs, or a compiler used to\line produce the work, or an object code interpreter used
to run it.\line \line The "Corresponding Source" for a work in object code form means all\line the source code needed to generate, install, and (for an executable\line work) run the object code and to modify the work, including scripts to\line control those activities. However
, it does not include the work's\line System Libraries, or general-purpose tools or generally available free\line programs which are used unmodified in performing those activities but\line which are not part of the work. For example, Corresponding Source\line includes interf
ace definition files associated with source files for\line the work, and the source code for shared libraries and dynamically\line linked subprograms that the work is specifically designed to require,\line such as by intimate data communication or control flow between th
ose\line subprograms and other parts of the work.\line \line The Corresponding Source need not include anything that users\line can regenerate automatically from other parts of the Corresponding\line Source.\line \line The Corresponding Source for a work in source code form is that\line same
work.\line \line 2. Basic Permissions.\line \line All rights granted under this License are granted for the term of\line copyright on the Program, and are irrevocable provided the stated\line conditions are met. This License explicitly affirms your unlimited\line permission to run the
unmodified Program. The output from running a\line covered work is covered by this License only if the output, given its\line content, constitutes a covered work. This License acknowledges your\line rights of fair use or other equivalent, as provided by copyright law.
\line \line You may make, run and propagate covered works that you do not\line convey, without conditions so long as your license otherwise remains\line in force. You may convey covered works to others for the sole purpose\line of having them make modifications exclusively for
you, or provide you\line with facilities for running those works, provided that you comply with\line the terms of this License in conveying all material for which you do\line not control copyright. Those thus making or running the covered works\line for you must do so exclus
ively on your behalf, under your direction\line and control, on terms that prohibit them from making any copies of\line your copyrighted material outside their relationship with you.\line \line Conveying under any other circumstances is permitted solely under\line the conditions
stated below. Sublicensing is not allowed; section 10\line makes it unnecessary.\line \line 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\line \line No covered work shall be deemed part of an effective technological\line measure under any applicable law fulfillin
g obligations under article\line 11 of the WIPO copyright treaty adopted on 20 December 1996, or\line similar laws prohibiting or restricting circumvention of such\line measures.\line \line When you convey a covered work, you waive any legal power to forbid\line circumvention of tech
nological measures to the extent such circumvention\line is effected by exercising rights under this License with respect to\line the covered work, and you disclaim any intention to limit operation or\line modification of the work as a means of enforcing, against the wor
k's\line users, your or third parties' legal rights to forbid circumvention of\line technological measures.\line \line 4. Conveying Verbatim Copies.\line \line You may convey verbatim copies of the Program's}
\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1035\i0\b0 source code as you\line receive it, in any medium, provided that you conspicuously and\line appropriately publish on each copy an appropriate copyright notice;\line keep intact all notices stating that this License and any\line non-permissive terms added in accord with secti
on 7 apply to the code;\line keep intact all notices of the absence of any warranty; and give all\line recipients a copy of this License along with the Program.\line \line You may charge any price or no price for each copy that you convey,\line and you may offer support or warra
nty protection for a fee.\line \line 5. Conveying Modified Source Versions.\line \line You may convey a work based on the Program, or the modifications to\line produce it from the Program, in the form of source code under the\line terms of section 4, provided that you also meet all
of these conditions:\line \line a) The work must carry prominent notices stating that you modified\line it, and giving a relevant date.\line \line b) The work must carry prominent notices stating that it is\line released under this License and any conditions added unde
r section\line 7. This requirement modifies the requirement in section 4 to\line "keep intact all notices".\line \line c) You must license the entire work, as a whole, under this\line License to anyone who comes into possession of a copy. This\line License will th
erefore apply, along with any applicable section 7\line additional terms, to the whole of the work, and all its parts,\line regardless of how they are packaged. This License gives no\line permission to license the work in any other way, but it does not\line i
nvalidate such permission if you have separately received it.\line \line d) If the work has interactive user interfaces, each must display\line Appropriate Legal Notices; however, if the Program has interactive\line interfaces that do not display Appropriate Legal
Notices, your\line work need not make them do so.\line \line A compilation of a covered work with other separate and independent\line works, which are not by their nature extensions of the covered work,\line and which are not combined with it such as to form a larger progra
m,\line in or on a volume of a storage or distribution medium, is called an\line "aggregate" if the compilation and its resulting copyright are not\line used to limit the access or legal rights of the compilation's users\line beyond what the individual works permit. Inclusio
n of a covered work\line in an aggregate does not cause this License to apply to the other\line parts of the aggregate.\line \line 6. Conveying Non-Source Forms.\line \line You may convey a covered work in object code form under the terms\line of sections 4 and 5, provided that you also
convey the\line machine-readable Corresponding Source under the terms of this License,\line in one of these ways:\line \line a) Convey the object code in, or embodied in, a physical product\line (including a physical distribution medium), accompanied by the\line Correspond
ing Source fixed on a durable physical medium\line customarily used for software interchange.\line \line b) Convey the object code in, or embodied in, a physical product\line (including a physical distribution medium), accompanied by a\line written offer, valid for
at least three years and valid for as\line long as you offer spare parts or customer support for that product\line model, to give anyone who possesses the object code either (1) a\line copy of the Corresponding Source for all the software in the\line product
that is covered by this License, on a durable physical\line medium customarily used for software interchange, for a price no\line more than your reasonable cost of physically performing this\line conveying of source, or (2) access to copy the\line Correspondin
g Source from a network server at no charge.\line \line c) Convey individual copies of the object code with a copy of the\line written offer to provide the Corresponding Source. This\line alternative is allowed only occasionally and noncommercially, and\line only
if you received the object code with such an offer, in accord\line with subsection 6b.\line \line d) Convey the object code by offering access from a designated\line place (gratis or for a charge), and offer equivalent access to the\line Corresponding Source in the
same way through the same place at no\line further charge. You need not require recipients to copy the\line Corresponding Source along with the object code. If the place to\line copy the object code is a network server, the Corresponding Source\line may be
on a different server (operated by you or a third party)\line that supports equivalent copying facilities, provided you maintain\line clear directions next to the object code saying where to find the\line Corresponding Source. Regardless of what server hosts
the\line Corresponding Source, you remain obligated to ensure that it is\line available for as long as needed to satisfy these requirements.\line \line e) Convey the object code using peer-to-peer transmission, provided\line you inform other peers where the object
code and Corresponding\line Source of the work are being offered to the general public at no\line charge under subsection 6d.\line \line A separable portion of the object code, whose source code is excluded\line from the Corresponding Source as a System Library, need no
t be\line included in conveying the object code work.\line \line A "User Product" is either (1) a "consumer product", which means any\line tangible personal property which is normally used for personal, family,\line or household purposes, or (2) anything designed or sold for inc
orporation\line into a dwelling. In determining whether a product is a consumer product,\line doubtful cases shall be resolved in favor of coverage. For a particular\line product received by a particular user, "normally used" refers to a\line typical or common use of that c
lass of product, regardless of the status\line of the particular user or of the way in which the particular user\line actually uses, or expects or is expected to use, the product. A product\line is a consumer product regardless of whether the product has substantial\line com
mercial, industrial or non-consumer uses, unless such uses represent\line the only significant mode of use of the product.\line \line "Installation Information" for a User Product means any methods,\line procedures, authorization keys, or other information required to insta
ll\line and execute modified versions of a covered work in that User Product from\line a modified version of its Corresponding Source. The information must\line suffice to ensure that the continued functioning of the modified object\line code is in no case prevented or inter
fered with solely because\line modification has been made.\line \line If you convey an object code work under this section in, or with, or\line specifically for use in, a User Product, and the conveying occurs as\line part of a transaction in which the right of possession and us
e of the\line User Product is transferred to the recipient in perpetuity or for a\line fixed term (regardless of how the transaction is characterized), the\line Corresponding Source conveyed under this section must be accompanied\line by the Installation Information. But thi
s requirement does not apply\line if neither you nor any third party retains the ability to install\line modified object code on the User Product (for example, the work has\line been installed in ROM).\line \line The requirement to provide Installation Information does not inclu
de a\line requirement to continue to provide support service, warranty, or updates\line for a work that has been modified or installed by the recipient, or for\line the User Product in which it has been modified or installed. Access to a\line network may be denied when the m
odification itself materially and\line adversely affects the operation of the network or violates the rules and\line protocols for communication across the network.\line \line Corresponding Source conveyed, and Installation Information provided,\line in accord with this section
must be in a format that is publicly\line documented (and with an implementation available to the public in\line source code form), and must require no special password or key for\line unpacking, reading or copying.\line \line 7. Additional Terms.\line \line "Additional permissions" are
terms that supplement the terms of this\line License by making exceptions from one or more of its conditions.\line Additional permissions that are applicable to the entire Program shall\line be treated as though they were included in this License, to the extent\line that the
y are valid under applicable law. If additional permissions\line apply only to part of the Program, that part may be used separately\line under those permissions, but the entire Program remains governed by\line this License without regard to the additional permissions.\line
\line When you convey a copy of a covered work, you may at your option\line remove any additional permissions from that copy, or from any part of\line it. (Additional permissions may be written to require their own\line removal in certain cases when you modify the work.)
You may place\line additional permissions on material, added by you to a covered work,\line for which you have or can give appropriate copyright permission.\line \line Notwithstanding any other provision of this License, for material you\line add to a covered work, you may (if a
uthorized by the copyright holders of\line that material) supplement the terms of this License with terms:\line \line a) Disclaiming warranty or limiting liability differently from the\line terms of sections 15 and 16 of this License; or\line \line b) Requiring preservation
of specified reasonable legal notices or\line author attributions in that material or in the Appropriate Legal\line Notices displayed by works containing it; or\line \line c) Prohibiting misrepresentation of the origin of that material, or\line requiring that modi
fied versions of such material be marked in\line reasonable ways as different from the original version; or\line \line d) Limiting the use for publicity purposes of names of licensors or\line authors of the material; or\line \line e) Declining to grant rights under trad
emark law for use of some\line trade names, trademarks, or service marks; or\line \line f) Requiring indemnification of licensors and authors of that\line material by anyone who conveys}
\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1035\i0\b0 the material (or modified versions of\line it) with contractual assumptions of liability to the recipient, for\line any liability that these contractual assumptions directly impose on\line those licensors and authors.\line \line All other non-permissive additional t
erms are considered "further\line restrictions" within the meaning of section 10. If the Program as you\line received it, or any part of it, contains a notice stating that it is\line governed by this License along with a term that is a further\line restriction, you may remov
e that term. If a license document contains\line a further restriction but permits relicensing or conveying under this\line License, you may add to a covered work material governed by the terms\line of that license document, provided that the further restriction does\line no
t survive such relicensing or conveying.\line \line If you add terms to a covered work in accord with this section, you\line must place, in the relevant source files, a statement of the\line additional terms that apply to those files, or a notice indicating\line where to find th
e applicable terms.\line \line Additional terms, permissive or non-permissive, may be stated in the\line form of a separately written license, or stated as exceptions;\line the above requirements apply either way.\line \line 8. Termination.\line \line You may not propagate or modify a cove
red work except as expressly\line provided under this License. Any attempt otherwise to propagate or\line modify it is void, and will automatically terminate your rights under\line this License (including any patent licenses granted under the third\line paragraph of section
11).\line \line However, if you cease all violation of this License, then your\line license from a particular copyright holder is reinstated (a)\line provisionally, unless and until the copyright holder explicitly and\line finally terminates your license, and (b) permanently, if
the copyright\line holder fails to notify you of the violation by some reasonable means\line prior to 60 days after the cessation.\line \line Moreover, your license from a particular copyright holder is\line reinstated permanently if the copyright holder notifies you of the\line vio
lation by some reasonable means, this is the first time you have\line received notice of violation of this License (for any work) from that\line copyright holder, and you cure the violation prior to 30 days after\line your receipt of the notice.\line \line Termination of your ri
ghts under this section does not terminate the\line licenses of parties who have received copies or rights from you under\line this License. If your rights have been terminated and not permanently\line reinstated, you do not qualify to receive new licenses for the same\line
material under section 10.\line \line 9. Acceptance Not Required for Having Copies.\line \line You are not required to accept this License in order to receive or\line run a copy of the Program. Ancillary propagation of a covered work\line occurring solely as a consequence of using
peer-to-peer transmission\line to receive a copy likewise does not require acceptance. However,\line nothing other than this License grants you permission to propagate or\line modify any covered work. These actions infringe copyright if you do\line not accept this License.
Therefore, by modifying or propagating a\line covered work, you indicate your acceptance of this License to do so.\line \line 10. Automatic Licensing of Downstream Recipients.\line \line Each time you convey a covered work, the recipient automatically\line receives a license from
the original licensors, to run, modify and\line propagate that work, subject to this License. You are not responsible\line for enforcing compliance by third parties with this License.\line \line An "entity transaction" is a transaction transferring control of an\line organizat
ion, or substantially all assets of one, or subdividing an\line organization, or merging organizations. If propagation of a covered\line work results from an entity transaction, each party to that\line transaction who receives a copy of the work also receives whatever\line l
icenses to the work the party's predecessor in interest had or could\line give under the previous paragraph, plus a right to possession of the\line Corresponding Source of the work from the predecessor in interest, if\line the predecessor has it or can get it with reason
able efforts.\line \line You may not impose any further restrictions on the exercise of the\line rights granted or affirmed under this License. For example, you may\line not impose a license fee, royalty, or other charge for exercise of\line rights granted under this License, a
nd you may not initiate litigation\line (including a cross-claim or counterclaim in a lawsuit) alleging that\line any patent claim is infringed by making, using, selling, offering for\line sale, or importing the Program or any portion of it.\line \line 11. Patents.\line \line A "contrib
utor" is a copyright holder who authorizes use under this\line License of the Program or a work on which the Program is based. The\line work thus licensed is called the contributor's "contributor version".\line \line A contributor's "essential patent claims" are all patent
claims\line owned or controlled by the contributor, whether already acquired or\line hereafter acquired, that would be infringed by some manner, permitted\line by this License, of making, using, or selling its contributor version,\line but do not include claims that would be
infringed only as a\line consequence of further modification of the contributor version. For\line purposes of this definition, "control" includes the right to grant\line patent sublicenses in a manner consistent with the requirements of\line this License.\line \line Each contributo
r grants you a non-exclusive, worldwide, royalty-free\line patent license under the contributor's essential patent claims, to\line make, use, sell, offer for sale, import and otherwise run, modify and\line propagate the contents of its contributor version.\line \line In the foll
owing three paragraphs, a "patent license" is any express\line agreement or commitment, however denominated, not to enforce a patent\line (such as an express permission to practice a patent or covenant not to\line sue for patent infringement). To "grant" such a patent l
icense to a\line party means to make such an agreement or commitment not to enforce a\line patent against the party.\line \line If you convey a covered work, knowingly relying on a patent license,\line and the Corresponding Source of the work is not available for anyone\line to copy,
free of charge and under the terms of this License, through a\line publicly available network server or other readily accessible means,\line then you must either (1) cause the Corresponding Source to be so\line available, or (2) arrange to deprive yourself of the benefi
t of the\line patent license for this particular work, or (3) arrange, in a manner\line consistent with the requirements of this License, to extend the patent\line license to downstream recipients. "Knowingly relying" means you have\line actual knowledge that, but for the pa
tent license, your conveying the\line covered work in a country, or your recipient's use of the covered work\line in a country, would infringe one or more identifiable patents in that\line country that you have reason to believe are valid.\line \line If, pursuant to or in connec
tion with a single transaction or\line arrangement, you convey, or propagate by procuring conveyance of, a\line covered work, and grant a patent license to some of the parties\line receiving the covered work authorizing them to use, propagate, modify\line or convey a specific
copy of the covered work, then the patent license\line you grant is automatically extended to all recipients of the covered\line work and works based on it.\line \line A patent license is "discriminatory" if it does not include within\line the scope of its coverage, prohibits t
he exercise of, or is\line conditioned on the non-exercise of one or more of the rights that are\line specifically granted under this License. You may not convey a covered\line work if you are a party to an arrangement with a third party that is\line in the business of distr
ibuting software, under which you make payment\line to the third party based on the extent of your activity of conveying\line the work, and under which the third party grants, to any of the\line parties who would receive the covered work from you, a discriminatory\line patent
license (a) in connection with copies of the covered work\line conveyed by you (or copies made from those copies), or (b) primarily\line for and in connection with specific products or compilations that\line contain the covered work, unless you entered into that arrange
ment,\line or that patent license was granted, prior to 28 March 2007.\line \line Nothing in this License shall be construed as excluding or limiting\line any implied license or other defenses to infringement that may\line otherwise be available to you under applicable patent la
w.\line \line 12. No Surrender of Others' Freedom.\line \line If conditions are imposed on you (whether by court order, agreement or\line otherwise) that contradict the conditions of this License, they do not\line excuse you from the conditions of this License. If you cannot conve
y a\line covered work so as to satisfy simultaneously your obligations under this\line License and any other pertinent obligations, then as a consequence you may\line not convey it at all. For example, if you agree to terms that obligate you\line to collect a royalty for fur
ther conveying from those to whom you convey\line the Program, the only way you could satisfy both those terms and this\line License would be to refrain entirely from conveying the Program.\line \line 13. Use with the GNU Affero General Public License.\line \line Notwithstanding an
y other provision of this License, you have\line permission to link or combine any covered work with a work licensed\line under version 3 of the GNU Affero General Public License into a single\line combined work, and to convey the resulting work. The terms of this\line Licen
se will continue to apply to the part which is the covered work,\line but the special requirements of the GNU Affero General Public License,\line section 13, concerning interaction through a network will apply to the\line combination as such.\line \line 14. Revised Versions of t
his License.\line \line The Free Software Foundation may publish revised and/or new versions of\line the GNU General Public License from time to time. Such new versions will\line be similar}
\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\langfe255\hich\f0\fs24\lang1035\loch\f0\fs24\lang1035 {\rtlch \ltrch\loch }{\rtlch \ltrch\loch\f0\fs24\lang1035\i0\b0 in spirit to the present version, but may differ in detail to\line address new problems or concerns.\line \line Each version is given a distinguishing version number. If the\line Program specifies that a certain numbered version of the GNU General\line Public License "or any l
ater version" applies to it, you have the\line option of following the terms and conditions either of that numbered\line version or of any later version published by the Free Software\line Foundation. If the Program does not specify a version number of the\line GNU General P
ublic License, you may choose any version ever published\line by the Free Software Foundation.\line \line If the Program specifies that a proxy can decide which future\line versions of the GNU General Public License can be used, that proxy's\line public statement of acceptance o
f a version permanently authorizes you\line to choose that version for the Program.\line \line Later license versions may give you additional or different\line permissions. However, no additional obligations are imposed on any\line author or copyright holder as a result of your
choosing to follow a\line later version.\line \line 15. Disclaimer of Warranty.\line \line THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\line APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\line HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
"AS IS" WITHOUT WARRANTY\line OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\line THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\line PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\line IS WITH YOU.
SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\line ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\line \line 16. Limitation of Liability.\line \line IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\line WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PAR
TY WHO MODIFIES AND/OR CONVEYS\line THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\line GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\line USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\line DA
TA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\line PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\line EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\line SUCH DAMAGES.\line \line 17. Interpretation
of Sections 15 and 16.\line \line If the disclaimer of warranty and limitation of liability provided\line above cannot be given local legal effect according to their terms,\line reviewing courts shall apply local law that most closely approximates\line an absolute waiver of all
civil liability in connection with the\line Program, unless a warranty or assumption of liability accompanies a\line copy of the Program in return for a fee.\line \line END OF TERMS AND CONDITIONS\line \line How to Apply These Terms to Your New Programs
\line \line If you develop a new program, and you want it to be of the greatest\line possible use to the public, the best way to achieve this is to make it\line free software which everyone can redistribute and change under these terms.\line \line To do so, attach the following not
ices to the program. It is safest\line to attach them to the start of each source file to most effectively\line state the exclusion of warranty; and each file should have at least\line the "copyright" line and a pointer to where the full notice is found.\line \line <one line
to give the program's name and a brief idea of what it does.>\line Copyright (C) <year> <name of author>\line \line This program is free software: you can redistribute it and/or modify\line it under the terms of the GNU General Public License as published by\line
the Free Software Foundation, either version 3 of the License, or\line (at your option) any later version.\line \line This program is distributed in the hope that it will be useful,\line but WITHOUT ANY WARRANTY; without even the implied warranty of\line MERCHANTAB
ILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\line GNU General Public License for more details.\line \line You should have received a copy of the GNU General Public License\line along with this program. If not, see <http://www.gnu.org/licenses/>.\line \line Also add
information on how to contact you by electronic and paper mail.\line \line If the program does terminal interaction, make it output a short\line notice like this when it starts in an interactive mode:\line \line <program> Copyright (C) <year> <name of author>\line This prog
ram comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\line This is free software, and you are welcome to redistribute it\line under certain conditions; type `show c' for details.\line \line The hypothetical commands `show w' and `show c' should show the ap
propriate\line parts of the General Public License. Of course, your program's commands\line might be different; for a GUI interface, you would use an "about box".\line \line You should also get your employer (if you work as a programmer) or school,\line if any, to sign a "copyr
ight disclaimer" for the program, if necessary.\line For more information on this, and how to apply and follow the GNU GPL, see\line <http://www.gnu.org/licenses/>.\line \line The GNU General Public License does not permit incorporating your program\line into proprietary program
s. If your program is a subroutine library, you\line may consider it more useful to permit linking proprietary applications with\line the library. If this is what you want to do, use the GNU Lesser General\line Public License instead of this License. But first, please
read\line <http://www.gnu.org/philosophy/why-not-lgpl.html>.\line }
\par }

View File

@ -12,7 +12,91 @@
<string>????</string>
<key>CFBundleExecutable</key>
<string>qtox</string>
<key>CFBundleDisplayName</key>
<string>qTox</string>
<key>CFBundleName</key>
<string>qTox</string>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0-EXPERIMENTIAL</string>
<key>CFBundleIdentifier</key>
<string>im.tox.qtox</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>Tox URL</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLSchemes</key>
<array>
<string>tox</string>
</array>
<key>CFBundleURLIconFile</key>
<string>qtox.icns</string>
</dict>
</array>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>tox</string>
</array>
<key>CFBundleTypeName</key>
<string>Tox profile</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleTypeIconFile</key>
<string>qtox.icns</string>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>tox/x-profile</string>
</array>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>public.tox</string>
</array>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeIdentifier</key>
<string>public.tox</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>com.apple.ostype</key>
<string>TOX</string>
<key>public.filename-extension</key>
<array>
<string>tox</string>
</array>
<key>public.mime-type</key>
<string>tox/x-profile</string>
</dict>
</dict>
</array>
<key>CFBundleLocalizations</key>
<array>
<string>en_US</string>
<string>en</string>
<string>bg_BG</string>
<string>de_DE</string>
<string>fi_FI</string>
<string>fr_FR</string>
<string>it_IT</string>
<string>pl_PL</string>
<string>ru_RU</string>
<string>uk_UA</string>
<string>sv</string>
</array>
</dict>
</plist>

27
res/makedist.sh Normal file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
PWD=`pwd`
echo "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>
<installer-gui-script minSpecVersion=\"1\">
<pkg-ref id=\"im.tox.qtox\"/>
<options hostArchitectures=\"x86_64\"/>
<title>qTox</title>
<license file=\"$PWD/gplv3.rtf\"/>
<welcome file=\"$PWD/welcome.txt\"/>
<domains enable_currentUserHome=\"true\" enable_localSystem=\"true\" enable_anywhere=\"true\"/>
<options customize=\"never\" require-scripts=\"false\"/>
<choices-outline>
<line choice=\"default\">
<line choice=\"im.tox.qtox\"/>
</line>
</choices-outline>
<allowed-os-versions>
<os-version min=\"10.7\"/>
</allowed-os-versions>
<choice id=\"default\"/>
<choice id=\"im.tox.qtox\" visible=\"false\">
<pkg-ref id=\"im.tox.qtox\"/>
</choice>
<pkg-ref id=\"im.tox.qtox\" version=\"1\" onConclusion=\"none\">qtox.pkg</pkg-ref>
</installer-gui-script>" > distribution.xml

12
res/welcome.txt Normal file
View File

@ -0,0 +1,12 @@
Welcome to the qTox for OS X internal nightly installer!
Please report all bugs to https://support.libtoxcore.so
########################################################
## WARNING: Install me to your user ONLY
##
## Failure to do so WILL break automatic updating
## and you WILL be left with and old and
## potentially broken qTox install!
##
########################################################

View File

@ -2,7 +2,7 @@
if which apt-get; then
sudo apt-get install build-essential qt5-qmake qt5-default libopenal-dev libopencv-dev \
libtool autotools-dev automake checkinstall check libopus-dev libvpx-dev
libtool autotools-dev automake checkinstall check libopus-dev libvpx-dev qttools5-dev-tools qtchooser
elif which pacman; then
sudo pacman -S --needed base-devel qt5 opencv openal opus libvpx
elif which yum; then

View File

@ -46,14 +46,14 @@ unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] =
#elif defined(Q_OS_OSX)
const QString AutoUpdater::platform = "osx";
const QString AutoUpdater::updaterBin = "installer -store -pkg "+Settings::getInstance().getSettingsDirPath()
+"/update/qtox.pkg -target /";
const QString AutoUpdater::updaterBin = "installer -pkg "+Settings::getInstance().getSettingsDirPath()
+"/update/qtox.pkg -target CurrentUserHomeDirectory";
const QString AutoUpdater::updateServer = "https://dist-build.tox.im";
unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] =
{
0xa5, 0x80, 0xf3, 0xb7, 0xd0, 0x10, 0xc0, 0xf9, 0xd6, 0xcf, 0x48, 0x15, 0x99, 0x70, 0x92, 0x49,
0xf6, 0xe8, 0xe5, 0xe2, 0x6c, 0x73, 0x8c, 0x48, 0x25, 0xed, 0x01, 0x72, 0xf7, 0x6c, 0x17, 0x28
0x9c, 0x7a, 0x0b, 0x2a, 0xe9, 0xdc, 0x33, 0xf7, 0x74, 0x9f, 0xec, 0x14, 0x29, 0x22, 0x06, 0x4b,
0xbe, 0x37, 0xe1, 0x9b, 0xb7, 0x18, 0xb4, 0xae, 0x8f, 0x29, 0x6b, 0x9d, 0xfe, 0xd6, 0x39, 0x3f
};
#else
@ -68,20 +68,22 @@ const QString AutoUpdater::filesURI = AutoUpdater::updateServer+"/qtox/"+AutoUpd
bool AutoUpdater::isUpdateAvailable()
{
QString newVersion = getUpdateVersion();
if (newVersion.isEmpty() || newVersion == GIT_VERSION)
VersionInfo newVersion = getUpdateVersion();
if (newVersion.timestamp <= TIMESTAMP
|| newVersion.versionString.isEmpty() || newVersion.versionString == GIT_VERSION)
return false;
else
return true;
}
QString AutoUpdater::getUpdateVersion()
AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion()
{
QString version;
VersionInfo versionInfo;
versionInfo.timestamp = 0;
// Updates only for supported platforms
if (platform.isEmpty())
return version;
return versionInfo;
QNetworkAccessManager *manager = new QNetworkAccessManager;
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI)));
@ -93,20 +95,20 @@ QString AutoUpdater::getUpdateVersion()
qWarning() << "AutoUpdater: getUpdateVersion: network error: "<<reply->errorString();
reply->deleteLater();
manager->deleteLater();
return version;
return versionInfo;
}
QByteArray data = reply->readAll();
reply->deleteLater();
manager->deleteLater();
if (data.size() < (int)(1+crypto_sign_BYTES))
return version;
return versionInfo;
// Check updater protocol version
if ((int)data[0] != '1')
if ((int)data[0] != '2')
{
qWarning() << "AutoUpdater: getUpdateVersion: Bad version "<<(uint8_t)data[0];
return version;
return versionInfo;
}
// Check the signature
@ -118,12 +120,16 @@ QString AutoUpdater::getUpdateVersion()
if (crypto_sign_verify_detached(sig, msg, msgData.size(), key) != 0)
{
qCritical() << "AutoUpdater: getUpdateVersion: RECEIVED FORGED VERSION FILE FROM "<<updateServer;
return version;
return versionInfo;
}
version = msgData;
int sepPos = msgData.indexOf('!');
versionInfo.timestamp = QString(msgData.left(sepPos)).toInt();
versionInfo.versionString = msgData.mid(sepPos+1);
return version;
qDebug() << "timestamp:"<<versionInfo.timestamp << ", str:"<<versionInfo.versionString;
return versionInfo;
}
QList<AutoUpdater::UpdateFileMeta> AutoUpdater::parseFlist(QByteArray flistData)

View File

@ -27,7 +27,7 @@
#ifdef Q_OS_WIN
#define AUTOUPDATE_ENABLED 1
#elif defined(Q_OS_OSX)
#define AUTOUPDATE_ENABLED 0
#define AUTOUPDATE_ENABLED 1
#else
#define AUTOUPDATE_ENABLED 0
#endif
@ -58,6 +58,12 @@ public:
QByteArray data;
};
struct VersionInfo
{
uint64_t timestamp;
QString versionString;
};
public:
/// Connects to the qTox update server, if an updat is found shows a dialog to the user asking to download it
/// Runs asynchronously in its own thread, and will return immediatly
@ -66,9 +72,9 @@ public:
/// Connects to the qTox update server, returns true if an update is available for download
/// Will call getUpdateVersion, and as such may block and processEvents
static bool isUpdateAvailable();
/// Fetch the version string of the last update available from the qTox update server
/// Fetch the version info of the last update available from the qTox update server
/// Will try to follow qTox's proxy settings, may block and processEvents
static QString getUpdateVersion();
static VersionInfo getUpdateVersion();
/// Will try to download an update, if successful returns true and qTox will apply it after a restart
/// Will try to follow qTox's proxy settings, may block and processEvents
static bool downloadUpdate();

View File

@ -45,12 +45,16 @@ const QString Core::CONFIG_FILE_NAME = "data";
const QString Core::TOX_EXT = ".tox";
QList<ToxFile> Core::fileSendQueue;
QList<ToxFile> Core::fileRecvQueue;
QHash<int, ToxGroupCall> Core::groupCalls;
QThread* Core::coreThread{nullptr};
Core::Core(Camera* cam, QThread *coreThread, QString loadPath) :
Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
tox(nullptr), camera(cam), loadPath(loadPath), ready{false}
{
qDebug() << "Core: loading Tox from" << loadPath;
coreThread = CoreThread;
videobuf = new uint8_t[videobufsize];
for (int i = 0; i < ptCounter; i++)
@ -95,12 +99,15 @@ Core::Core(Camera* cam, QThread *coreThread, QString loadPath) :
}
QString inDevDescr = Settings::getInstance().getInDev();
int stereoFlag = av_DefaultSettings.audio_channels==1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
if (inDevDescr.isEmpty())
alInDev = alcCaptureOpenDevice(nullptr,av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16,
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4) / 1000);
alInDev = alcCaptureOpenDevice(nullptr,av_DefaultSettings.audio_sample_rate, stereoFlag,
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
/ 1000 * av_DefaultSettings.audio_channels);
else
alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(),av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16,
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4) / 1000);
alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(),av_DefaultSettings.audio_sample_rate, stereoFlag,
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
/ 1000 * av_DefaultSettings.audio_channels);
if (!alInDev)
qWarning() << "Core: Cannot open input audio device";
}
@ -262,6 +269,7 @@ void Core::start()
tox_callback_group_invite(tox, onGroupInvite, this);
tox_callback_group_message(tox, onGroupMessage, this);
tox_callback_group_namelist_change(tox, onGroupNamelistChange, this);
tox_callback_group_title(tox, onGroupTitleChange, this);
tox_callback_group_action(tox, onGroupAction, this);
tox_callback_file_send_request(tox, onFileSendRequestCallback, this);
tox_callback_file_control(tox, onFileControlCallback, this);
@ -481,15 +489,16 @@ void Core::onGroupAction(Tox*, int groupnumber, int peernumber, const uint8_t *a
void Core::onGroupInvite(Tox*, int friendnumber, uint8_t type, const uint8_t *data, uint16_t length,void *core)
{
QByteArray pk((char*)data, length);
if (type == TOX_GROUPCHAT_TYPE_TEXT)
{
qDebug() << QString("Core: Text group invite by %1").arg(friendnumber);
emit static_cast<Core*>(core)->groupInviteReceived(friendnumber,type,data,length);
emit static_cast<Core*>(core)->groupInviteReceived(friendnumber,type,pk);
}
else if (type == TOX_GROUPCHAT_TYPE_AV)
{
qDebug() << QString("Core: AV group invite by %1").arg(friendnumber);
emit static_cast<Core*>(core)->groupInviteReceived(friendnumber,type,data,length);
emit static_cast<Core*>(core)->groupInviteReceived(friendnumber,type,pk);
}
else
{
@ -510,6 +519,16 @@ void Core::onGroupNamelistChange(Tox*, int groupnumber, int peernumber, uint8_t
emit static_cast<Core*>(core)->groupNamelistChanged(groupnumber, peernumber, change);
}
void Core::onGroupTitleChange(Tox*, int groupnumber, int peernumber, const uint8_t* title, uint8_t len, void* _core)
{
qDebug() << "Core: group" << groupnumber << "title changed by" << peernumber;
Core* core = static_cast<Core*>(_core);
QString author;
if (peernumber >= 0)
author = core->getGroupPeerName(groupnumber, peernumber);
emit core->groupTitleChanged(groupnumber, author, CString::toString(title, len));
}
void Core::onFileSendRequestCallback(Tox*, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
const uint8_t *filename, uint16_t filename_length, void *core)
{
@ -808,6 +827,14 @@ void Core::sendGroupAction(int groupId, const QString& message)
}
}
void Core::changeGroupTitle(int groupId, const QString& title)
{
CString cTitle(title);
int err = tox_group_set_title(tox, groupId, cTitle.data(), cTitle.size());
if (!err)
emit groupTitleChanged(groupId, getUsername(), title);
}
void Core::sendFile(int32_t friendId, QString Filename, QString FilePath, long long filesize)
{
QMutexLocker mlocker(&fileSendMutex);
@ -1631,11 +1658,17 @@ void Core::groupInviteFriend(int friendId, int groupId)
void Core::createGroup(uint8_t type)
{
if (type == TOX_GROUPCHAT_TYPE_TEXT)
{
emit emptyGroupCreated(tox_add_groupchat(tox));
}
else if (type == TOX_GROUPCHAT_TYPE_AV)
{
emit emptyGroupCreated(toxav_add_av_groupchat(tox, playGroupAudio, this));
}
else
{
qWarning() << "Core::createGroup: Unknown type "<<type;
}
}
bool Core::hasFriendWithAddress(const QString &addr) const

View File

@ -95,10 +95,11 @@ public slots:
void setStatusMessage(const QString& message);
void setAvatar(uint8_t format, const QByteArray& data);
int sendMessage(int friendId, const QString& message);
int sendMessage(int friendId, const QString& message);
void sendGroupMessage(int groupId, const QString& message);
void sendGroupAction(int groupId, const QString& message);
int sendAction(int friendId, const QString& action);
void changeGroupTitle(int groupId, const QString& title);
int sendAction(int friendId, const QString& action);
void sendTyping(int friendId, bool typing);
void sendFile(int32_t friendId, QString Filename, QString FilePath, long long filesize);
@ -117,6 +118,15 @@ public slots:
void micMuteToggle(int callId);
void volMuteToggle(int callId);
static void joinGroupCall(int groupId); ///< Starts a call in an existing AV groupchat
static void leaveGroupCall(int groupId); ///< Will not leave the group, just stop the call
static void disableGroupCallMic(int groupId);
static void disableGroupCallVol(int groupId);
static void enableGroupCallMic(int groupId);
static void enableGroupCallVol(int groupId);
static bool isGroupCallMicEnabled(int groupId);
static bool isGroupCallVolEnabled(int groupId);
void setPassword(QString& password, PasswordType passtype, uint8_t* salt = nullptr);
void clearPassword(PasswordType passtype);
QByteArray encryptData(const QByteArray& data, PasswordType passtype);
@ -145,9 +155,10 @@ signals:
void friendLastSeenChanged(int friendId, const QDateTime& dateTime);
void emptyGroupCreated(int groupnumber);
void groupInviteReceived(int friendnumber, uint8_t type, const uint8_t *group_public_key,uint16_t length);
void groupInviteReceived(int friendnumber, uint8_t type, QByteArray publicKey);
void groupMessageReceived(int groupnumber, const QString& message, const QString& author, bool isAction);
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
void groupTitleChanged(int groupnumber, const QString& author, const QString& title);
void usernameSet(const QString& username);
void statusMessageSet(const QString& message);
@ -157,6 +168,7 @@ signals:
void messageSentResult(int friendId, const QString& message, int messageId);
void groupSentResult(int groupId, const QString& message, int result);
void actionSentResult(int friendId, const QString& action, int success);
void receiptRecieved(int friedId, int receipt);
@ -212,6 +224,7 @@ private:
static void onGroupInvite(Tox *tox, int friendnumber, uint8_t type, const uint8_t *data, uint16_t length,void *userdata);
static void onGroupMessage(Tox *tox, int groupnumber, int friendgroupnumber, const uint8_t * message, uint16_t length, void *userdata);
static void onGroupNamelistChange(Tox *tox, int groupnumber, int peernumber, uint8_t change, void *userdata);
static void onGroupTitleChange(Tox*, int groupnumber, int peernumber, const uint8_t* title, uint8_t len, void* _core);
static void onFileSendRequestCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
const uint8_t *filename, uint16_t filename_length, void *userdata);
static void onFileControlCallback(Tox *tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
@ -235,6 +248,7 @@ private:
static void playGroupAudio(Tox* tox, int groupnumber, int friendgroupnumber, const int16_t* out_audio,
unsigned out_audio_samples, uint8_t decoder_channels, unsigned audio_sample_rate, void* userdata);
static void sendGroupCallAudio(int groupId, ToxAv* toxav);
static void prepareCall(int friendId, int callId, ToxAv *toxav, bool videoEnabled);
static void cleanupCall(int callId);
@ -268,6 +282,7 @@ private:
int dhtServerId;
static QList<ToxFile> fileSendQueue, fileRecvQueue;
static ToxCall calls[];
static QHash<int, ToxGroupCall> groupCalls; // Maps group IDs to ToxGroupCalls
QMutex fileSendMutex, messageSendMutex;
bool ready;
@ -278,6 +293,8 @@ private:
static ALCdevice* alOutDev, *alInDev;
static ALCcontext* alContext;
static QThread *coreThread;
public:
static ALuint alMainSource;
};

View File

@ -48,7 +48,9 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled
calls[callId].codecSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
calls[callId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
calls[callId].videoEnabled = videoEnabled;
toxav_prepare_transmission(toxav, callId, av_jbufdc, av_VADd, videoEnabled);
int r = toxav_prepare_transmission(toxav, callId, av_jbufdc, av_VADd, videoEnabled);
if (r < 0)
qWarning() << QString("Error starting call %1: toxav_prepare_transmission failed with %2").arg(callId).arg(r);
// Audio
alGenSources(1, &calls[callId].alSource);
@ -176,7 +178,6 @@ void Core::startCall(int friendId, bool video)
emit avCallFailed(friendId);
return;
}
}
}
@ -222,7 +223,7 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
return;
}
int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000;
int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000 * av_DefaultSettings.audio_channels;
uint8_t buf[framesize*2], dest[framesize*2];
bool frame = false;
@ -230,6 +231,7 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
if(samples >= framesize)
{
memset(buf, 0, framesize*2); // Avoid uninitialized values (Valgrind)
alcCaptureSamples(alInDev, buf, framesize);
frame = 1;
}
@ -547,7 +549,7 @@ void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, un
}
ALuint bufid;
ALint processed, queued;
ALint processed = 0, queued = 16;
alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);
alSourcei(alSource, AL_LOOPING, AL_FALSE);
@ -559,7 +561,7 @@ void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, un
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
}
else if(queued < 16)
else if(queued < 128)
{
alGenBuffers(1, &bufid);
}
@ -578,7 +580,7 @@ void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, un
if(state != AL_PLAYING)
{
alSourcePlay(alSource);
qDebug() << "Core: Starting audio source " << (int)alSource;
//qDebug() << "Core: Starting audio source " << (int)alSource;
}
}
@ -587,10 +589,122 @@ VideoSource *Core::getVideoSourceFromCall(int callNumber)
return &calls[callNumber].videoSource;
}
void Core::playGroupAudio(Tox* /*tox*/, int /*groupnumber*/, int /*friendgroupnumber*/, const int16_t* out_audio,
void Core::playGroupAudio(Tox* /*tox*/, int groupnumber, int friendgroupnumber, const int16_t* out_audio,
unsigned out_audio_samples, uint8_t decoder_channels, unsigned audio_sample_rate, void* /*userdata*/)
{
/// TODO: FIXME: Don't play groupchat audio on the main source!
/// We'll need some sort of call[] array but for groupchats, when that's done use this source
playAudioBuffer(alMainSource, out_audio, out_audio_samples, decoder_channels, audio_sample_rate);
if (!groupCalls[groupnumber].active)
return;
if (groupCalls[groupnumber].muteVol)
return;
if (!groupCalls[groupnumber].alSources.contains(friendgroupnumber))
alGenSources(1, &groupCalls[groupnumber].alSources[friendgroupnumber]);
playAudioBuffer(groupCalls[groupnumber].alSources[friendgroupnumber], out_audio,
out_audio_samples, decoder_channels, audio_sample_rate);
}
void Core::joinGroupCall(int groupId)
{
qDebug() << QString("Core: Joining group call %1").arg(groupId);
groupCalls[groupId].groupId = groupId;
groupCalls[groupId].muteMic = false;
groupCalls[groupId].muteVol = false;
// the following three lines are also now redundant from startCall, but are
// necessary there for outbound and here for inbound
groupCalls[groupId].codecSettings = av_DefaultSettings;
groupCalls[groupId].codecSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
groupCalls[groupId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
// Audio
//alGenSources(1, &groupCalls[groupId].alSource);
alcCaptureStart(alInDev);
// Go
ToxAv* toxav = Core::getInstance()->toxav;
groupCalls[groupId].sendAudioTimer = new QTimer();
groupCalls[groupId].sendAudioTimer->moveToThread(coreThread);
groupCalls[groupId].active = true;
groupCalls[groupId].sendAudioTimer->setInterval(5);
groupCalls[groupId].sendAudioTimer->setSingleShot(true);
connect(groupCalls[groupId].sendAudioTimer, &QTimer::timeout, [=](){sendGroupCallAudio(groupId,toxav);});
groupCalls[groupId].sendAudioTimer->start();
}
void Core::leaveGroupCall(int groupId)
{
qDebug() << QString("Core: Leaving group call %1").arg(groupId);
groupCalls[groupId].active = false;
disconnect(groupCalls[groupId].sendAudioTimer,0,0,0);
groupCalls[groupId].sendAudioTimer->stop();
alcCaptureStop(alInDev);
}
void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
{
if (!groupCalls[groupId].active)
return;
if (groupCalls[groupId].muteMic)
{
groupCalls[groupId].sendAudioTimer->start();
return;
}
int framesize = (groupCalls[groupId].codecSettings.audio_frame_duration * groupCalls[groupId].codecSettings.audio_sample_rate) / 1000 * av_DefaultSettings.audio_channels;
uint8_t buf[framesize*2];
bool frame = false;
ALint samples;
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
if(samples >= framesize)
{
memset(buf, 0, framesize*2); // Avoid uninitialized values (Valgrind)
alcCaptureSamples(alInDev, buf, framesize);
frame = 1;
}
if(frame)
{
int r;
if((r = toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf,
framesize, av_DefaultSettings.audio_channels, av_DefaultSettings.audio_sample_rate)) < 0)
{
qDebug() << "Core: toxav_group_send_audio error";
groupCalls[groupId].sendAudioTimer->start();
return;
}
}
groupCalls[groupId].sendAudioTimer->start();
}
void Core::disableGroupCallMic(int groupId)
{
groupCalls[groupId].muteMic = true;
}
void Core::disableGroupCallVol(int groupId)
{
groupCalls[groupId].muteVol = true;
}
void Core::enableGroupCallMic(int groupId)
{
groupCalls[groupId].muteMic = false;
}
void Core::enableGroupCallVol(int groupId)
{
groupCalls[groupId].muteVol = false;
}
bool Core::isGroupCallMicEnabled(int groupId)
{
return !groupCalls[groupId].muteMic;
}
bool Core::isGroupCallVolEnabled(int groupId)
{
return !groupCalls[groupId].muteVol;
}

View File

@ -1,6 +1,7 @@
#ifndef COREAV_H
#define COREAV_H
#include <QHash>
#include <tox/toxav.h>
#include "video/netvideosource.h"
@ -16,7 +17,6 @@ class QTimer;
struct ToxCall
{
public:
ToxAvCSettings codecSettings;
QTimer *sendAudioTimer, *sendVideoTimer;
int callId;
@ -29,4 +29,15 @@ public:
NetVideoSource videoSource;
};
struct ToxGroupCall
{
ToxAvCSettings codecSettings;
QTimer *sendAudioTimer;
int groupId;
bool active;
bool muteMic;
bool muteVol;
QHash<int, ALuint> alSources;
};
#endif // COREAV_H

View File

@ -23,8 +23,8 @@
#include <QDebug>
#include <QTimer>
Group::Group(int GroupId, QString Name)
: groupId(GroupId), nPeers{0}
Group::Group(int GroupId, QString Name, bool IsAvGroupchat)
: groupId(GroupId), nPeers{0}, avGroupchat{IsAvGroupchat}
{
widget = new GroupWidget(groupId, Name);
chatForm = new GroupChatForm(this);
@ -69,3 +69,9 @@ void Group::updatePeer(int peerId, QString name)
widget->onUserListChanged();
chatForm->onUserListChanged();
}
void Group::setName(const QString& name)
{
widget->setName(name);
chatForm->setName(name);
}

View File

@ -30,11 +30,12 @@ class Group : public QObject
{
Q_OBJECT
public:
Group(int GroupId, QString Name);
Group(int GroupId, QString Name, bool IsAvGroupchat);
~Group();
void addPeer(int peerId, QString name);
void removePeer(int peerId);
void updatePeer(int peerId, QString newName);
void setName(const QString& name);
public:
int groupId;
@ -43,6 +44,7 @@ public:
GroupWidget* widget;
GroupChatForm* chatForm;
int hasNewMessages, userWasMentioned;
bool avGroupchat;
};
#endif // GROUP_H

View File

@ -19,9 +19,9 @@
QList<Group*> GroupList::groupList;
Group* GroupList::addGroup(int groupId, const QString& name)
Group* GroupList::addGroup(int groupId, const QString& name, bool isAvGroupchat)
{
Group* newGroup = new Group(groupId, name);
Group* newGroup = new Group(groupId, name, isAvGroupchat);
groupList.append(newGroup);
return newGroup;
}

View File

@ -26,7 +26,7 @@ class GroupList
{
public:
GroupList();
static Group* addGroup(int groupId, const QString& name);
static Group* addGroup(int groupId, const QString& name, bool isAvGroupchat);
static Group* findGroup(int groupId);
static void removeGroup(int groupId, bool fake = false);

View File

@ -130,6 +130,8 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
updateChatsID();
updateAliases();
setSyncType(Settings::getInstance().getDbSyncType());
QSqlQuery sqlAnswer = db->exec("select seq from sqlite_sequence where name=\"history\";");
sqlAnswer.first();
messageID = sqlAnswer.value(0).toInt();
@ -145,10 +147,12 @@ int HistoryKeeper::addChatEntry(const QString& chat, const QString& message, con
int chat_id = getChatID(chat, ctSingle).first;
int sender_id = getAliasID(sender);
db->exec("BEGIN TRANSACTION");
db->exec(QString("INSERT INTO history (timestamp, chat_id, sender, message)") +
QString("VALUES (%1, %2, %3, '%4');")
.arg(dt.toMSecsSinceEpoch()).arg(chat_id).arg(sender_id).arg(wrapMessage(message)));
db->exec(QString("INSERT INTO sent_status (status) VALUES (%1)").arg(isSent));
db->exec("COMMIT TRANSACTION");
messageID++;
return messageID;
@ -315,3 +319,25 @@ void HistoryKeeper::markAsSent(int m_id)
{
db->exec(QString("UPDATE sent_status SET status = 1 WHERE id = %1;").arg(m_id));
}
void HistoryKeeper::setSyncType(Db::syncType sType)
{
QString syncCmd;
switch (sType) {
case Db::syncType::stFull:
syncCmd = "FULL";
break;
case Db::syncType::stNormal:
syncCmd = "NORMAL";
break;
case Db::syncType::stOff:
syncCmd = "OFF";
break;
default:
syncCmd = "FULL";
break;
}
db->exec(QString("PRAGMA synchronous=%1;").arg(syncCmd));
}

View File

@ -22,6 +22,7 @@
#include <QDateTime>
class GenericDdInterface;
namespace Db { enum class syncType; }
class HistoryKeeper
{
@ -51,6 +52,8 @@ public:
QList<HistMessage> getChatHistory(ChatType ct, const QString &chat, const QDateTime &time_from, const QDateTime &time_to);
void markAsSent(int m_id);
void setSyncType(Db::syncType sType);
private:
HistoryKeeper(GenericDdInterface *db_);
HistoryKeeper(HistoryKeeper &hk) = delete;
@ -68,7 +71,6 @@ private:
GenericDdInterface *db;
QMap<QString, int> aliases;
QMap<QString, QPair<int, ChatType>> chats;
bool isEncrypted;
int messageID;
};

View File

@ -71,7 +71,9 @@ IPC::~IPC()
{
if (globalMemory.lock())
{
*(time_t*)((char*)globalMemory.data()+sizeof(globalId)) = 0;
char* data = (char*)globalMemory.data();
if (data)
*(time_t*)(data+sizeof(globalId)) = 0;
globalMemory.unlock();
}
}
@ -132,7 +134,7 @@ void IPC::processEvents()
}
else
{
qWarning() << "IPC:processEvents failed to lock";
//qWarning() << "IPC:processEvents failed to lock";
goto restartTimer;
}

View File

@ -94,7 +94,7 @@ int main(int argc, char *argv[])
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
a.addLibraryPath("platforms");
qDebug() << "built on: " << __TIME__ << __DATE__;
qDebug() << "built on: " << __TIME__ << __DATE__ << "(" << TIMESTAMP << ")";
qDebug() << "commit: " << GIT_VERSION << "\n";
// Install Unicode 6.1 supporting font
@ -146,6 +146,11 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS;
}
}
else
{
fprintf(stderr, "Invalid argument\n");
return EXIT_FAILURE;
}
}
// Run

View File

@ -21,6 +21,10 @@
#include <QSqlDatabase>
namespace Db {
enum class syncType : int {stOff = 0, stNormal = 1, stFull = 2};
}
class PlainDb : public GenericDdInterface
{
public:

View File

@ -17,6 +17,7 @@
#include "settings.h"
#include "smileypack.h"
#include "src/corestructs.h"
#include "src/misc/db/plaindb.h"
#include <QFont>
#include <QApplication>
@ -112,6 +113,7 @@ void Settings::load()
s.beginGroup("General");
enableIPv6 = s.value("enableIPv6", true).toBool();
translation = s.value("translation", "en").toString();
showSystemTray = s.value("showSystemTray", false).toBool();
makeToxPortable = s.value("makeToxPortable", false).toBool();
autostartInTray = s.value("autostartInTray", false).toBool();
closeToTray = s.value("closeToTray", false).toBool();
@ -120,12 +122,17 @@ void Settings::load()
proxyAddr = s.value("proxyAddr", "").toString();
proxyPort = s.value("proxyPort", 0).toInt();
currentProfile = s.value("currentProfile", "").toString();
autoAwayTime = s.value("autoAwayTime", 10).toInt();
autoAwayTime = s.value("autoAwayTime", 10).toInt();
checkUpdates = s.value("checkUpdates", false).toBool();
showInFront = s.value("showInFront", false).toBool();
fauxOfflineMessaging = s.value("fauxOfflineMessaging", true).toBool();
s.endGroup();
s.beginGroup("Advanced");
int sType = s.value("dbSyncType", static_cast<int>(Db::syncType::stFull)).toInt();
setDbSyncType(sType);
s.endGroup();
s.beginGroup("Widgets");
QList<QString> objectNames = s.childKeys();
for (const QString& name : objectNames) {
@ -138,7 +145,7 @@ void Settings::load()
smileyPack = s.value("smileyPack", ":/smileys/cylgom/emoticons.xml").toString();
customEmojiFont = s.value("customEmojiFont", true).toBool();
emojiFontFamily = s.value("emojiFontFamily", "DejaVu Sans").toString();
emojiFontPointSize = s.value("emojiFontPointSize", QApplication::font().pointSize()).toInt();
emojiFontPointSize = s.value("emojiFontPointSize", 12).toInt();
firstColumnHandlePos = s.value("firstColumnHandlePos", 50).toInt();
secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt();
timestampFormat = s.value("timestampFormat", "hh:mm").toString();
@ -252,6 +259,7 @@ void Settings::save(QString path)
s.setValue("enableIPv6", enableIPv6);
s.setValue("translation",translation);
s.setValue("makeToxPortable",makeToxPortable);
s.setValue("showSystemTray", showSystemTray);
s.setValue("autostartInTray",autostartInTray);
s.setValue("closeToTray", closeToTray);
s.setValue("useProxy", useProxy);
@ -265,6 +273,10 @@ void Settings::save(QString path)
s.setValue("fauxOfflineMessaging", fauxOfflineMessaging);
s.endGroup();
s.beginGroup("Advanced");
s.setValue("dbSyncType", static_cast<int>(dbSyncType));
s.endGroup();
s.beginGroup("Widgets");
const QList<QString> widgetNames = widgetSettings.keys();
for (const QString& name : widgetNames) {
@ -430,6 +442,16 @@ void Settings::setStyle(const QString& newStyle)
style = newStyle;
}
bool Settings::getShowSystemTray() const
{
return showSystemTray;
}
void Settings::setShowSystemTray(const bool& newValue)
{
showSystemTray = newValue;
}
void Settings::setUseEmoticons(bool newValue)
{
useEmoticons = newValue;
@ -585,6 +607,19 @@ void Settings::setEncryptTox(bool newValue)
encryptTox = newValue;
}
Db::syncType Settings::getDbSyncType() const
{
return dbSyncType;
}
void Settings::setDbSyncType(int newValue)
{
if (newValue >= 0 && newValue <= 2)
dbSyncType = static_cast<Db::syncType>(newValue);
else
dbSyncType = Db::syncType::stFull;
}
int Settings::getAutoAwayTime() const
{
return autoAwayTime;

View File

@ -21,7 +21,8 @@
#include <QObject>
#include <QPixmap>
class ToxID;
struct ToxID;
namespace Db { enum class syncType; }
class Settings : public QObject
{
@ -62,6 +63,9 @@ public:
QString getStyle() const;
void setStyle(const QString& newValue);
bool getShowSystemTray() const;
void setShowSystemTray(const bool& newValue);
bool getUseEmoticons() const;
void setUseEmoticons(bool newValue);
@ -96,6 +100,9 @@ public:
bool getEncryptTox() const;
void setEncryptTox(bool newValue);
Db::syncType getDbSyncType() const;
void setDbSyncType(int newValue);
int getAutoAwayTime() const;
void setAutoAwayTime(int newValue);
@ -265,7 +272,8 @@ private:
QByteArray windowState;
QByteArray splitterState;
QString style;
bool showSystemTray;
// ChatView
int firstColumnHandlePos;
int secondColumnHandlePosFromRight;
@ -274,6 +282,7 @@ private:
// Privacy
bool typingNotification;
Db::syncType dbSyncType;
// Audio
QString inDev;

View File

@ -43,8 +43,6 @@
ChatForm::ChatForm(Friend* chatFriend)
: f(chatFriend)
, audioInputFlag(false)
, audioOutputFlag(false)
, callId(0)
{
nameLabel->setText(f->getDisplayedName());

View File

@ -95,8 +95,6 @@ private:
Friend* f;
CroppingLabel *statusMessageLabel;
NetCamView* netcam;
bool audioInputFlag;
bool audioOutputFlag;
int callId;
QLabel *callDuration;
QTimer *timer;

View File

@ -37,6 +37,8 @@
GenericChatForm::GenericChatForm(QWidget *parent) :
QWidget(parent),
earliestMessage(nullptr)
, audioInputFlag(false)
, audioOutputFlag(false)
{
curRow = 0;

View File

@ -91,6 +91,8 @@ protected:
QPushButton *sendButton;
ChatAreaWidget *chatWidget;
QDateTime *earliestMessage;
bool audioInputFlag;
bool audioOutputFlag;
};
#endif // GENERICCHATFORM_H

View File

@ -28,21 +28,31 @@
#include <QDragEnterEvent>
#include "src/historykeeper.h"
#include "src/misc/flowlayout.h"
#include <QDebug>
GroupChatForm::GroupChatForm(Group* chatGroup)
: group(chatGroup)
: group(chatGroup), inCall{false}
{
nusersLabel = new QLabel();
tabber = new TabCompleter(msgEdit, group);
fileButton->setEnabled(false);
callButton->setVisible(false);
videoButton->setVisible(false);
volButton->setVisible(false);
micButton->setVisible(false);
if (group->avGroupchat)
{
videoButton->setEnabled(false);
videoButton->setObjectName("grey");
}
else
{
videoButton->setVisible(false);
callButton->setVisible(false);
volButton->setVisible(false);
micButton->setVisible(false);
}
nameLabel->setText(group->widget->getName());
nameLabel->setEditable(true);
nusersLabel->setFont(Style::getFont(Style::Medium));
nusersLabel->setText(GroupChatForm::tr("%1 users in chat","Number of users in chat").arg(group->peers.size()));
@ -68,6 +78,10 @@ GroupChatForm::GroupChatForm(Group* chatGroup)
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
connect(msgEdit, &ChatTextEdit::tabPressed, tabber, &TabCompleter::complete);
connect(msgEdit, &ChatTextEdit::keyPressed, tabber, &TabCompleter::reset);
connect(callButton, &QPushButton::clicked, this, &GroupChatForm::onCallClicked);
connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
connect(nameLabel, &CroppingLabel::textChanged, this, [=](QString s, QString) {emit groupTitleChanged(group->groupId, s);} );
setAcceptDrops(true);
}
@ -129,3 +143,104 @@ void GroupChatForm::dropEvent(QDropEvent *ev)
}
}
void GroupChatForm::onMicMuteToggle()
{
if (audioInputFlag == true)
{
if (micButton->objectName() == "red")
{
Core::getInstance()->enableGroupCallMic(group->groupId);
micButton->setObjectName("green");
}
else
{
Core::getInstance()->disableGroupCallMic(group->groupId);
micButton->setObjectName("red");
}
Style::repolish(micButton);
}
}
void GroupChatForm::onVolMuteToggle()
{
if (audioOutputFlag == true)
{
if (volButton->objectName() == "red")
{
Core::getInstance()->enableGroupCallVol(group->groupId);
volButton->setObjectName("green");
}
else
{
Core::getInstance()->disableGroupCallVol(group->groupId);
volButton->setObjectName("red");
}
Style::repolish(volButton);
}
}
void GroupChatForm::onCallClicked()
{
if (!inCall)
{
Core::getInstance()->joinGroupCall(group->groupId);
audioInputFlag = true;
audioOutputFlag = true;
callButton->setObjectName("red");
callButton->style()->polish(callButton);
inCall = true;
}
else
{
Core::getInstance()->leaveGroupCall(group->groupId);
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
micButton->style()->polish(micButton);
volButton->setObjectName("green");
volButton->style()->polish(volButton);
callButton->setObjectName("green");
callButton->style()->polish(callButton);
inCall = false;
}
}
void GroupChatForm::keyPressEvent(QKeyEvent* ev)
{
if (msgEdit->hasFocus())
return;
// Push to talk
if (ev->key() == Qt::Key_P && inCall)
{
Core* core = Core::getInstance();
if (!core->isGroupCallMicEnabled(group->groupId))
{
core->enableGroupCallMic(group->groupId);
micButton->setObjectName("green");
micButton->style()->polish(micButton);
Style::repolish(micButton);
}
}
}
void GroupChatForm::keyReleaseEvent(QKeyEvent* ev)
{
if (msgEdit->hasFocus())
return;
// Push to talk
if (ev->key() == Qt::Key_P && inCall)
{
Core* core = Core::getInstance();
if (core->isGroupCallMicEnabled(group->groupId))
{
core->disableGroupCallMic(group->groupId);
micButton->setObjectName("red");
micButton->style()->polish(micButton);
Style::repolish(micButton);
}
}
}

View File

@ -32,8 +32,17 @@ public:
void onUserListChanged();
void keyPressEvent(QKeyEvent* ev);
void keyReleaseEvent(QKeyEvent* ev);
signals:
void groupTitleChanged(int groupnum, const QString& name);
private slots:
void onSendTriggered();
void onMicMuteToggle();
void onVolMuteToggle();
void onCallClicked();
protected:
// drag & drop
@ -45,6 +54,7 @@ private:
FlowLayout* namesListLayout;
QLabel *nusersLabel;
TabCompleter* tabber;
bool inCall;
};
#endif // GROUPCHATFORM_H

View File

@ -0,0 +1,62 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#include "ui_advancedsettings.h"
#include "advancedform.h"
#include "src/historykeeper.h"
#include "src/misc/settings.h"
#include "src/misc/db/plaindb.h"
AdvancedForm::AdvancedForm() :
GenericForm(tr("Advanced"), QPixmap(":/img/settings/general.png"))
{
bodyUI = new Ui::AdvancedSettings;
bodyUI->setupUi(this);
bodyUI->dbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
bodyUI->dbLabel->setOpenExternalLinks(true);
bodyUI->syncTypeComboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
bodyUI->syncTypeComboBox->addItems({"FULL - very safe, slowest (recommended)",
"NORMAL - almost as safe as FULL, about 20% faster than FULL",
"OFF - disables all safety, when something goes wrong your history may be lost, fastest (not recommended)"
});
int index = 2 - static_cast<int>(Settings::getInstance().getDbSyncType());
bodyUI->syncTypeComboBox->setCurrentIndex(index);
connect(bodyUI->syncTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onDbSyncTypeUpdated()));
connect(bodyUI->resetButton, SIGNAL(clicked()), this, SLOT(resetToDefault()));
}
AdvancedForm::~AdvancedForm()
{
delete bodyUI;
}
void AdvancedForm::onDbSyncTypeUpdated()
{
int index = 2 - bodyUI->syncTypeComboBox->currentIndex();
Settings::getInstance().setDbSyncType(index);
HistoryKeeper::getInstance()->setSyncType(Settings::getInstance().getDbSyncType());
}
void AdvancedForm::resetToDefault()
{
int index = 2 - static_cast<int>(Db::syncType::stFull);
bodyUI->syncTypeComboBox->setCurrentIndex(index);
onDbSyncTypeUpdated();
}

View File

@ -0,0 +1,43 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#ifndef ADVANCEDFORM_H
#define ADVANCEDFORM_H
#include "genericsettings.h"
class Core;
namespace Ui {
class AdvancedSettings;
}
class AdvancedForm : public GenericForm
{
Q_OBJECT
public:
AdvancedForm();
virtual ~AdvancedForm();
private slots:
void onDbSyncTypeUpdated();
void resetToDefault();
private:
Ui::AdvancedSettings* bodyUI;
};
#endif // ADVANCEDFORM_H

View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdvancedSettings</class>
<widget class="QWidget" name="AdvancedSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>380</width>
<height>280</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="warningLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; color:#ff0000;&quot;&gt;IMPORTANT NOTE&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;Unless you &lt;/span&gt;&lt;span style=&quot; font-weight:600; color:#ff0000;&quot;&gt;really&lt;/span&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt; know what you are doing, please do &lt;/span&gt;&lt;span style=&quot; font-weight:600; color:#ff0000;&quot;&gt;not&lt;/span&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt; change anything here. Changes made here may lead to problems with qTox, and even to loss of your data, e.g. history.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QPushButton" name="resetButton">
<property name="text">
<string>Reset to default settings</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QGroupBox" name="historyGroup">
<property name="title">
<string>History</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="dbLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;http://www.sqlite.org/pragma.html#pragma_synchronous&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Synchronous writing to DB&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="syncTypeComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -51,6 +51,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
bodyUI->transComboBox->insertItem(i, langs[i]);
bodyUI->transComboBox->setCurrentIndex(locales.indexOf(Settings::getInstance().getTranslation()));
bodyUI->cbMakeToxPortable->setChecked(Settings::getInstance().getMakeToxPortable());
bodyUI->showSystemTray->setChecked(Settings::getInstance().getShowSystemTray());
bodyUI->startInTray->setChecked(Settings::getInstance().getAutostartInTray());
bodyUI->closeToTray->setChecked(Settings::getInstance().getCloseToTray());
bodyUI->minimizeToTray->setChecked(Settings::getInstance().getMinimizeToTray());
@ -104,6 +105,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
connect(bodyUI->checkUpdates, &QCheckBox::stateChanged, this, &GeneralForm::onCheckUpdateChanged);
connect(bodyUI->transComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onTranslationUpdated()));
connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated);
connect(bodyUI->showSystemTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetShowSystemTray);
connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray);
connect(bodyUI->closeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetCloseToTray);
connect(bodyUI->minimizeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetMinimizeToTray);
@ -150,6 +152,12 @@ void GeneralForm::onMakeToxPortableUpdated()
Settings::getInstance().setMakeToxPortable(bodyUI->cbMakeToxPortable->isChecked());
}
void GeneralForm::onSetShowSystemTray()
{
Settings::getInstance().setShowSystemTray(bodyUI->showSystemTray->isChecked());
emit parent->setShowSystemTray(bodyUI->showSystemTray->isChecked());
}
void GeneralForm::onSetAutostartInTray()
{
Settings::getInstance().setAutostartInTray(bodyUI->startInTray->isChecked());

View File

@ -34,6 +34,7 @@ private slots:
void onEnableIPv6Updated();
void onTranslationUpdated();
void onMakeToxPortableUpdated();
void onSetShowSystemTray();
void onSetAutostartInTray();
void onSetCloseToTray();
void onSmileyBrowserIndexChanged(int index);

View File

@ -39,8 +39,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>511</width>
<height>698</height>
<width>583</width>
<height>748</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
@ -95,6 +95,13 @@
</item>
<item>
<layout class="QHBoxLayout" name="trayLayout">
<item>
<widget class="QCheckBox" name="showSystemTray">
<property name="text">
<string>Show system tray</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="startInTray">
<property name="sizePolicy">
@ -190,9 +197,6 @@
<property name="toolTip">
<string>Set to 0 to disable</string>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> minutes</string>
</property>
@ -202,6 +206,9 @@
<property name="maximum">
<number>2147483647</number>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@ -503,5 +510,54 @@
</layout>
</widget>
<resources/>
<connections/>
<connections>
<connection>
<sender>showSystemTray</sender>
<signal>toggled(bool)</signal>
<receiver>startInTray</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>125</x>
<y>122</y>
</hint>
<hint type="destinationlabel">
<x>207</x>
<y>124</y>
</hint>
</hints>
</connection>
<connection>
<sender>showSystemTray</sender>
<signal>toggled(bool)</signal>
<receiver>closeToTray</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>66</x>
<y>119</y>
</hint>
<hint type="destinationlabel">
<x>346</x>
<y>116</y>
</hint>
</hints>
</connection>
<connection>
<sender>showSystemTray</sender>
<signal>toggled(bool)</signal>
<receiver>minimizeToTray</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>83</x>
<y>121</y>
</hint>
<hint type="destinationlabel">
<x>476</x>
<y>120</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -22,6 +22,7 @@
#include "src/widget/form/settings/identityform.h"
#include "src/widget/form/settings/privacyform.h"
#include "src/widget/form/settings/avform.h"
#include "src/widget/form/settings/advancedform.h"
#include <QTabWidget>
SettingsWidget::SettingsWidget(QWidget* parent)
@ -54,8 +55,9 @@ SettingsWidget::SettingsWidget(QWidget* parent)
IdentityForm* ifrm = new IdentityForm;
PrivacyForm* pfrm = new PrivacyForm;
AVForm* avfrm = new AVForm;
AdvancedForm *expfrm = new AdvancedForm;
GenericForm* cfgForms[] = { gfrm, ifrm, pfrm, avfrm };
GenericForm* cfgForms[] = { gfrm, ifrm, pfrm, avfrm, expfrm };
for (GenericForm* cfgForm : cfgForms)
settingsWidgets->addTab(cfgForm, cfgForm->getFormIcon(), cfgForm->getFormName());

View File

@ -45,6 +45,9 @@ public:
private slots:
void onTabChanged(int);
signals:
void setShowSystemTray(bool newValue);
private:
QWidget *head, *body; // keep the others private
IdentityForm *ifrm;

View File

@ -122,3 +122,23 @@ void GroupWidget::dropEvent(QDropEvent *ev)
Core::getInstance()->groupInviteFriend(friendId, groupId);
}
}
void GroupWidget::keyPressEvent(QKeyEvent* ev)
{
Group* g = GroupList::findGroup(groupId);
if (g)
g->chatForm->keyPressEvent(ev);
}
void GroupWidget::keyReleaseEvent(QKeyEvent* ev)
{
Group* g = GroupList::findGroup(groupId);
if (g)
g->chatForm->keyReleaseEvent(ev);
}
void GroupWidget::setName(const QString& name)
{
nameLabel->setText(name);
}

View File

@ -32,6 +32,7 @@ public:
void updateStatusLight();
void setChatForm(Ui::MainWindow &);
void resetEventFlags();
void setName(const QString& name);
signals:
void groupWidgetClicked(GroupWidget* widget);
@ -41,6 +42,8 @@ protected:
// drag & drop
void dragEnterEvent(QDragEnterEvent* ev);
void dropEvent(QDropEvent* ev);
void keyPressEvent(QKeyEvent* ev);
void keyReleaseEvent(QKeyEvent* ev);
public:
int groupId;

View File

@ -20,7 +20,7 @@
#include <QWidget>
class QHBoxLayout;
class vpx_image;
struct vpx_image;
class VideoSurface;
class VideoSource;

View File

@ -96,7 +96,9 @@ void Widget::init()
this,
SLOT(onIconClick(QSystemTrayIcon::ActivationReason)));
icon->show();
if (Settings::getInstance().getShowSystemTray()){
icon->show();
}
if(Settings::getInstance().getAutostartInTray() == false)
this->show();
@ -171,6 +173,7 @@ void Widget::init()
ui->statusButton->setEnabled(false);
idleTimer = new QTimer();
idleTimer->setSingleShot(true);
int mins = Settings::getInstance().getAutoAwayTime();
if (mins > 0)
idleTimer->start(mins * 1000*60);
@ -196,6 +199,8 @@ void Widget::init()
addFriendForm = new AddFriendForm;
settingsWidget = new SettingsWidget();
connect(settingsWidget, SIGNAL(setShowSystemTray(bool)), this, SLOT(onSetShowSystemTray(bool)));
connect(core, &Core::connected, this, &Widget::onConnected);
connect(core, &Core::disconnected, this, &Widget::onDisconnected);
connect(core, &Core::failedToStart, this, &Widget::onFailedToStartCore);
@ -217,6 +222,7 @@ void Widget::init()
connect(core, &Core::groupInviteReceived, this, &Widget::onGroupInviteReceived);
connect(core, &Core::groupMessageReceived, this, &Widget::onGroupMessageReceived);
connect(core, &Core::groupNamelistChanged, this, &Widget::onGroupNamelistChanged);
connect(core, &Core::groupTitleChanged, this, &Widget::onGroupTitleChanged);
connect(core, &Core::emptyGroupCreated, this, &Widget::onEmptyGroupCreated);
connect(core, &Core::avInvite, this, &Widget::playRingtone);
connect(core, &Core::blockingClearContacts, this, &Widget::clearContactsList, Qt::BlockingQueuedConnection);
@ -497,6 +503,7 @@ void Widget::onStatusSet(Status status)
{
case Status::Online:
ui->statusButton->setProperty("status" ,"online");
qDebug() << "Widget: something set the status to online";
break;
case Status::Away:
ui->statusButton->setProperty("status" ,"away");
@ -841,7 +848,7 @@ void Widget::removeFriend(Friend* f, bool fake)
FriendList::removeFriend(f->getFriendID(), fake);
core->removeFriend(f->getFriendID(), fake);
delete f;
if (ui->mainHead->layout()->isEmpty()) // tux3: this should have covered the case of the bug you "fixed" 5 lines above
if (ui->mainHead->layout()->isEmpty())
onAddClicked();
contactListWidget->hide();
@ -872,11 +879,11 @@ void Widget::copyFriendIdToClipboard(int friendId)
}
}
void Widget::onGroupInviteReceived(int32_t friendId, uint8_t type, const uint8_t* publicKey,uint16_t length)
void Widget::onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray invite)
{
if (type == TOX_GROUPCHAT_TYPE_TEXT || type == TOX_GROUPCHAT_TYPE_AV)
{
int groupId = core->joinGroupchat(friendId, type, publicKey,length);
int groupId = core->joinGroupchat(friendId, type, (uint8_t*)invite.data(), invite.length());
if (groupId < 0)
{
qWarning() << "Widget::onGroupInviteReceived: Unable to accept group invite";
@ -921,7 +928,7 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha
Group* g = GroupList::findGroup(groupnumber);
if (!g)
{
qDebug() << "Widget::onGroupNamelistChanged: Group not found, creating it";
qDebug() << "Widget::onGroupNamelistChanged: Group "<<groupnumber<<" not found, creating it";
g = createGroup(groupnumber);
}
@ -945,6 +952,17 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha
g->updatePeer(peernumber,core->getGroupPeerName(groupnumber, peernumber));
}
void Widget::onGroupTitleChanged(int groupnumber, const QString& author, const QString& title)
{
Group* g = GroupList::findGroup(groupnumber);
if (!g)
return;
g->setName(title);
if (!author.isEmpty())
g->chatForm->addSystemInfoMessage(tr("%1 has set the title to %2").arg(author, title), "silver", QDateTime::currentDateTime());
}
void Widget::removeGroup(Group* g, bool fake)
{
g->widget->setAsInactiveChatroom();
@ -983,7 +1001,7 @@ Group *Widget::createGroup(int groupId)
}
QString groupName = QString("Groupchat #%1").arg(groupId);
Group* newgroup = GroupList::addGroup(groupId, groupName);
Group* newgroup = GroupList::addGroup(groupId, groupName, true);
QLayout* layout = contactListWidget->getGroupLayout();
layout->addWidget(newgroup->widget);
newgroup->widget->updateStatusLight();
@ -993,6 +1011,7 @@ Group *Widget::createGroup(int groupId)
connect(newgroup->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), newgroup->chatForm, SLOT(focusInput()));
connect(newgroup->chatForm, SIGNAL(sendMessage(int,QString)), core, SLOT(sendGroupMessage(int,QString)));
connect(newgroup->chatForm, SIGNAL(sendAction(int,QString)), core, SLOT(sendGroupAction(int,QString)));
connect(newgroup->chatForm, &GroupChatForm::groupTitleChanged, core, &Core::changeGroupTitle);
return newgroup;
}
@ -1026,9 +1045,9 @@ bool Widget::event(QEvent * e)
case QEvent::Wheel:
case QEvent::KeyPress:
case QEvent::KeyRelease:
if (autoAwayActive)
{
qDebug() << "Widget: auto away deactivated";
if (autoAwayActive && ui->statusButton->property("status").toString() == "away")
{ // be sure nothing else has changed the status in the meantime
qDebug() << "Widget: auto away deactivated at" << QTime::currentTime().toString();
autoAwayActive = false;
emit statusSet(Status::Online);
int mins = Settings::getInstance().getAutoAwayTime();
@ -1047,7 +1066,7 @@ void Widget::onUserAway()
if (Settings::getInstance().getAutoAwayTime() > 0
&& ui->statusButton->property("status").toString() == "online") // leave user-set statuses in place
{
qDebug() << "Widget: auto away activated";
qDebug() << "Widget: auto away activated" << QTime::currentTime().toString();
emit statusSet(Status::Away);
autoAwayActive = true;
}
@ -1103,6 +1122,11 @@ void Widget::getPassword(QString info, int passtype, uint8_t* salt)
}
}
void Widget::onSetShowSystemTray(bool newValue){
icon->setVisible(newValue);
}
QMessageBox::StandardButton Widget::showWarningMsgBox(const QString& title, const QString& msg, QMessageBox::StandardButtons buttons)
{
// We can only display widgets from the GUI thread
@ -1160,4 +1184,4 @@ void Widget::clearAllReceipts()
{
f->getChatForm()->clearReciepts();
}
}
}

View File

@ -112,9 +112,10 @@ private slots:
void onFriendRequestReceived(const QString& userId, const QString& message);
void onReceiptRecieved(int friendId, int receipt);
void onEmptyGroupCreated(int groupId);
void onGroupInviteReceived(int32_t friendId, uint8_t type, const uint8_t *publicKey,uint16_t length);
void onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray invite);
void onGroupMessageReceived(int groupnumber, const QString& message, const QString& author, bool isAction);
void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
void onGroupTitleChanged(int groupnumber, const QString& author, const QString& title);
void removeFriend(int friendId);
void copyFriendIdToClipboard(int friendId);
void removeGroup(int groupId);
@ -127,6 +128,7 @@ private slots:
void onIconClick(QSystemTrayIcon::ActivationReason);
void onUserAway();
void getPassword(QString info, int passtype, uint8_t* salt);
void onSetShowSystemTray(bool newValue);
private:
void init();

View File

@ -1,3 +0,0 @@
#!/bin/bash
./qtox-updater-genflist /var/www/html/qtox/win32/

View File

@ -1,4 +1,4 @@
#!/bin/bash
echo -n 1 > /var/www/html/qtox/win32/version
./qtox-updater-sign $1 >> /var/www/html/qtox/win32/version
echo -n 2 > version
./qtox-updater-sign `date +%s`!$1 >> version

337
translations/fr.ts vendored
View File

@ -115,9 +115,15 @@
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="100"/>
<source>qTox needs to use the Tox DNS, but can&apos;t do it through a proxy.
Ignore the proxy and connect to the Internet directly ?</source>
<translation>qTox as besoin d&apos;utiliser le DNS Tox, mais ne peut pas le faire avec un proxy.
Ignorer le proxy et se connecter directement à Internet ?</translation>
</message>
<message>
<source>qTox needs to use the Tox DNS, but can&apos;t do it through a proxy
Ignore the proxy and connect to the Internet directly ?</source>
<translation>qTox as besoin d&apos;utiliser le DNS Tox, mais ne peut pas le faire avec un proxy
<translation type="vanished">qTox as besoin d&apos;utiliser le DNS Tox, mais ne peut pas le faire avec un proxy
Ignorer le proxy et se connecter directement à Internet ?</translation>
</message>
<message>
@ -160,52 +166,52 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<context>
<name>ChatForm</name>
<message>
<location filename="../src/widget/form/chatform.cpp" line="67"/>
<location filename="../src/widget/form/chatform.cpp" line="66"/>
<source>Load History...</source>
<translation>Charger l&apos;historique...</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="122"/>
<location filename="../src/widget/form/chatform.cpp" line="138"/>
<source>Send a file</source>
<translation>Envoyer un fichier</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="132"/>
<location filename="../src/widget/form/chatform.cpp" line="148"/>
<source>Bad Idea</source>
<translation>Mauvaise Idée</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="132"/>
<location filename="../src/widget/form/chatform.cpp" line="148"/>
<source>You&apos;re trying to send a special (sequential) file, that&apos;s not going to work!</source>
<translation>Vous êtes en train d&apos;essayer d&apos;envoyer un fichier spécial (sequentiel), ça ne marchera pas!</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="238"/>
<location filename="../src/widget/form/chatform.cpp" line="254"/>
<source>%1 calling</source>
<translation>%1 appelle</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="307"/>
<location filename="../src/widget/form/chatform.cpp" line="323"/>
<source>%1 stopped calling</source>
<translation>%1a arreté l&apos;appel</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="363"/>
<location filename="../src/widget/form/chatform.cpp" line="379"/>
<source>Calling to %1</source>
<translation>Appel de %1 en cours</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="504"/>
<location filename="../src/widget/form/chatform.cpp" line="520"/>
<source>Call rejected</source>
<translation>Appel rejeté</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="763"/>
<location filename="../src/widget/form/chatform.cpp" line="804"/>
<source>Call with %1 ended. %2</source>
<translation>Appel avec %1 terminé. %2</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="783"/>
<location filename="../src/widget/form/chatform.cpp" line="823"/>
<source>Call duration: </source>
<translation>Durée de l&apos;appel:</translation>
</message>
@ -221,99 +227,104 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<context>
<name>Core</name>
<message>
<location filename="../src/core.cpp" line="249"/>
<location filename="../src/core.cpp" line="256"/>
<source>Toxing on qTox</source>
<translation>Toxer avec qTox</translation>
</message>
<message>
<location filename="../src/core.cpp" line="250"/>
<location filename="../src/core.cpp" line="257"/>
<source>qTox User</source>
<translation>Utilisateur de qTox</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1140"/>
<location filename="../src/core.cpp" line="746"/>
<source>Friend is already added</source>
<translation>Cet ami est déjà dans cos contact</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1176"/>
<source>Encryption error</source>
<translation>Erreur de chiffrement</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1140"/>
<location filename="../src/core.cpp" line="1176"/>
<source>The .tox file is encrypted, but encryption was not checked, continuing regardless.</source>
<translation>Le fichier .tox est chiffré, mais l&apos;encryption n&apos;as pas été activée. Le problème sera ignoré.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1147"/>
<location filename="../src/core.cpp" line="1183"/>
<source>Tox datafile decryption password</source>
<translation>Mot de passe des données Tox</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1149"/>
<location filename="../src/core.cpp" line="1161"/>
<location filename="../src/core.cpp" line="1225"/>
<location filename="../src/core.cpp" line="1185"/>
<location filename="../src/core.cpp" line="1197"/>
<location filename="../src/core.cpp" line="1261"/>
<source>Password error</source>
<translation>Mod de passe invalide</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1149"/>
<location filename="../src/core.cpp" line="1225"/>
<location filename="../src/core.cpp" line="1185"/>
<location filename="../src/core.cpp" line="1261"/>
<source>Failed to setup password.
Empty password.</source>
<translation>Impossible de mettre ne place le mot de passe.
Le mot de passe est vide.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1157"/>
<location filename="../src/core.cpp" line="1193"/>
<source>Try Again</source>
<translation>Réessayer</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1158"/>
<location filename="../src/core.cpp" line="1194"/>
<source>Change profile</source>
<translation>Changer de profil</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1159"/>
<location filename="../src/core.cpp" line="1195"/>
<source>Reinit current profile</source>
<translation>Réinitialiser le profil courant</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1162"/>
<location filename="../src/core.cpp" line="1198"/>
<source>Wrong password has been entered</source>
<translation>Un mauvais mot de passe à été entré</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1223"/>
<location filename="../src/core.cpp" line="1259"/>
<source>History Log decryption password</source>
<translation>Mot de passe de l&apos;historique</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1231"/>
<location filename="../src/core.cpp" line="1267"/>
<source>Your history is encrypted with different password
Do you want to try another password?</source>
<translation>Votre historique de conversation est chiffré avec un autre mot de passe
Voulez-vous essayer un mot de passe différent?</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1230"/>
<location filename="../src/core.cpp" line="1266"/>
<source>Encrypted log</source>
<translation>Historique chiffré</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1241"/>
<location filename="../src/core.cpp" line="1277"/>
<source>Loggin</source>
<translation>Historique</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1241"/>
<location filename="../src/core.cpp" line="1277"/>
<source>Due to incorret password logging will be disabled</source>
<translation>À cause d&apos;un mauvais mot de passe, l&apos;historique sera désactivé</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1314"/>
<location filename="../src/core.cpp" line="1350"/>
<source>NO Password</source>
<translation>PAS de mot de passe</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1314"/>
<location filename="../src/core.cpp" line="1350"/>
<source>Will be saved without encryption!</source>
<translation>L&apos;historique sera sauvegardé sans être chiffré!</translation>
</message>
@ -465,30 +476,30 @@ Voulez-vous essayer un mot de passe différent?</translation>
<context>
<name>GeneralForm</name>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="36"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="38"/>
<source>General</source>
<translation>Général</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="63"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="69"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="71"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="77"/>
<source>None</source>
<translation>Aucun</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="198"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="209"/>
<source>Choose an auto accept directory</source>
<comment>popup title</comment>
<translation>Choisir un dossier de téléchargement</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="255"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="266"/>
<source>Call active</source>
<comment>popup title</comment>
<translation>Appel en cours</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="256"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="267"/>
<source>You can&apos;t disconnect while a call is active!</source>
<comment>popup text</comment>
<translation>Vous ne pouvez pas vous déconnecter avec un appel en cours!</translation>
@ -527,27 +538,27 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation>Rendre Tox portable</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="99"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="107"/>
<source>Start in tray</source>
<translation>Démarrer dans la barre d&apos;état</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="106"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="120"/>
<source>Close to tray</source>
<translation>Fermer dans la barre d&apos;état</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="113"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="133"/>
<source>Minimize to tray</source>
<translation>Minimizer dans la barre d&apos;état</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="120"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="142"/>
<source>Show contacts&apos; status changes</source>
<translation>Montrer les changements de status des contacts</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="129"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="172"/>
<source>Provided in minutes</source>
<translation>En minutes</translation>
</message>
@ -556,17 +567,17 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation type="vanished">Auto-absent après (0 pour désactiver):</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="148"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="191"/>
<source>Set to 0 to disable</source>
<translation>Mettre à 0 pour désactiver</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="154"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="197"/>
<source> minutes</source>
<translation> minutes</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="203"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="250"/>
<source>Theme</source>
<translation>Thème</translation>
</message>
@ -600,19 +611,19 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation type="vanished">Style:</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="397"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="444"/>
<source>Enable UDP (recommended)</source>
<extracomment>Text on checkbox to disable UDP</extracomment>
<translation>Activer UDP (recommandé)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="445"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="492"/>
<source>Reconnect</source>
<comment>reconnect button</comment>
<translation>Reconnection</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="375"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="422"/>
<source>Connection Settings</source>
<translation>Options de réseau</translation>
</message>
@ -622,67 +633,87 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation>Traduction</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="135"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="149"/>
<source>Check for updates on startup (unstable)</source>
<translation>Chercher des mises à jour au démarrage (instable)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="156"/>
<source>Focus qTox when a message is received</source>
<translation>Montrer qTox quand un message est reçu</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="163"/>
<source>Faux offline messaging</source>
<translation>Retransmettre les messages en cas d&apos;échec</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="178"/>
<source>Auto away after (0 to disable)</source>
<translation>Indisponible après (0 désactive)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="169"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="214"/>
<source>Autoaccept files</source>
<translation>Auto-accepter les fichiers</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="178"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="223"/>
<source>Save files in</source>
<translation>Sauvegarder les fichiers vers</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="191"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="236"/>
<source>PushButton</source>
<translation>PushButton</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="209"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="256"/>
<source>Use emoticons</source>
<translation>Utiliser les émoticones</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="218"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="265"/>
<source>Smiley Pack</source>
<extracomment>Text on smiley pack label</extracomment>
<translation>Pack de smileys</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="296"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="343"/>
<source>Style</source>
<translation>Style</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="317"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="364"/>
<source>Emoticon size</source>
<translation>Taille d&apos;émoticone</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="333"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="380"/>
<source> px</source>
<translation>px</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="353"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="400"/>
<source>Timestamp format</source>
<translation>Format de timestamp</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="387"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="434"/>
<source>Enable IPv6 (recommended)</source>
<extracomment>Text on a checkbox to enable IPv6</extracomment>
<translation>Activer IPv6 (recommandé)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="394"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="441"/>
<source>Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.</source>
<extracomment>force tcp checkbox tooltip</extracomment>
<translation>Désactiver ceci permet par exemple d&apos;utiliser Tox à travers Tor, mais ce n&apos;est à utiliser que si nécessaire, car cela ralenti le réseau Tox.</translation>
</message>
<message>
<source>This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary.</source>
<extracomment>force tcp checkbox tooltip</extracomment>
<translation>Permet par exemple d&apos;utiliser Tox à travers Tor, mais ce n&apos;est à utiliser que si nécessaire, car cela ralenti le réseau Tox.</translation>
<translation type="vanished">Permet par exemple d&apos;utiliser Tox à travers Tor, mais ce n&apos;est à utiliser que si nécessaire, car cela ralenti le réseau Tox.</translation>
</message>
<message>
<source>Disable UDP (not recommended)</source>
@ -690,18 +721,18 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation type="vanished">Désactiver UDP (non recommandé)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="404"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="451"/>
<source>Use proxy (SOCKS5)</source>
<translation>Utiliser un proxy (SOCKS5)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="416"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="463"/>
<source>Address</source>
<extracomment>Text on proxy addr label</extracomment>
<translation>Addresse</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="426"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="473"/>
<source>Port</source>
<extracomment>Text on proxy port label</extracomment>
<translation>Port</translation>
@ -710,53 +741,53 @@ Voulez-vous essayer un mot de passe différent?</translation>
<context>
<name>GenericChatForm</name>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="60"/>
<location filename="../src/widget/form/genericchatform.cpp" line="62"/>
<source>Send message</source>
<translation>Envoyer un message</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="62"/>
<location filename="../src/widget/form/genericchatform.cpp" line="64"/>
<source>Smileys</source>
<translation>Emoticones</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="66"/>
<location filename="../src/widget/form/genericchatform.cpp" line="68"/>
<source>Send file(s)</source>
<translation>Envoyer des fichiers</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="69"/>
<location filename="../src/widget/form/genericchatform.cpp" line="71"/>
<source>Audio call</source>
<translation>Appel audio</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="72"/>
<location filename="../src/widget/form/genericchatform.cpp" line="74"/>
<source>Video call</source>
<translation>Appel vidéo</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="75"/>
<location filename="../src/widget/form/genericchatform.cpp" line="77"/>
<source>Toggle speakers volume</source>
<translation>Couper les haut parleurs</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="78"/>
<location filename="../src/widget/form/genericchatform.cpp" line="80"/>
<source>Toggle microphone</source>
<translation>Couper le microphone</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="142"/>
<location filename="../src/widget/form/genericchatform.cpp" line="182"/>
<location filename="../src/widget/form/genericchatform.cpp" line="144"/>
<location filename="../src/widget/form/genericchatform.cpp" line="186"/>
<source>Save chat log</source>
<translation>Sauvegarder l&apos;historique de conversation</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="143"/>
<location filename="../src/widget/form/genericchatform.cpp" line="145"/>
<source>Clear displayed messages</source>
<translation>Effacer les messages affichés</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="289"/>
<location filename="../src/widget/form/genericchatform.cpp" line="303"/>
<source>Cleared</source>
<translation>Effacé</translation>
</message>
@ -764,13 +795,13 @@ Voulez-vous essayer un mot de passe différent?</translation>
<context>
<name>GroupChatForm</name>
<message>
<location filename="../src/widget/form/groupchatform.cpp" line="48"/>
<location filename="../src/widget/form/groupchatform.cpp" line="57"/>
<source>%1 users in chat</source>
<comment>Number of users in chat</comment>
<translation>%1 personnes</translation>
</message>
<message>
<location filename="../src/widget/form/groupchatform.cpp" line="94"/>
<location filename="../src/widget/form/groupchatform.cpp" line="106"/>
<source>%1 users in chat</source>
<translation>%1 personnes</translation>
</message>
@ -804,103 +835,123 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation>Identité</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="125"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="132"/>
<source>Call active</source>
<comment>popup title</comment>
<translation>Appel en cours</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="126"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="133"/>
<source>You can&apos;t switch profiles while a call is active!</source>
<comment>popup text</comment>
<translation>Vous ne pouvez pas changer de profil quand un appel est en cours!</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="136"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="143"/>
<source>Rename &quot;%1&quot;</source>
<comment>renaming a profile</comment>
<translation>Renommer &quot;%1&quot;</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="144"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="151"/>
<source>Profile already exists</source>
<comment>rename confirm title</comment>
<translation>Ce profil existe déjà</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="145"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="152"/>
<source>A profile named &quot;%1&quot; already exists. Do you want to erase it?</source>
<comment>rename confirm text</comment>
<translation>Un profil appelé &quot;%1&quot; existe déjà. Voulez-vous le supprimer ?</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="159"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="166"/>
<source>Export profile</source>
<comment>save dialog title</comment>
<translation>Exporter le profil</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="161"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="168"/>
<source>Tox save file (*.tox)</source>
<comment>save dialog filter</comment>
<translation>Fichier sauvegarde Tox (*.tox)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="170"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="180"/>
<source>Failed to remove file</source>
<translation>Impossible de supprimer le fichier</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="180"/>
<source>The file you chose to overwrite could not be removed first.</source>
<translation>Le fichier que vous avez choisi d&apos;écraser n&apos;as pas pu être supprimé.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="186"/>
<source>Failed to copy file</source>
<translation>Impossible de copier le fichier</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="186"/>
<source>The file you chose could not be written to.</source>
<translation>Le fichier que vous avez choisi n&apos;as pas pu être écrit.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="194"/>
<source>Profile currently loaded</source>
<comment>current profile deletion warning title</comment>
<translation>Profil en cours d&apos;utilisation</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="170"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="194"/>
<source>This profile is currently in use. Please load a different profile before deleting this one.</source>
<comment>current profile deletion warning text</comment>
<translation>Ce profil est en cours d&apos;utilisation. Merci de choisir un autre profil avant de supprimer celui-ci.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="174"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="198"/>
<source>Deletion imminent!</source>
<comment>deletion confirmation title</comment>
<translation>Suppression imminente!</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="175"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="199"/>
<source>Are you sure you want to delete this profile?</source>
<comment>deletion confirmation text</comment>
<translation>Êtes-vous sur de vouloir supprimer ce profil ?</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="187"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="211"/>
<source>Import profile</source>
<comment>import dialog title</comment>
<translation>Importer un profil</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="189"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="213"/>
<source>Tox save file (*.tox)</source>
<comment>import dialog filter</comment>
<translation>Fichier sauvegarde Tox (*.tox)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="199"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="223"/>
<source>Ignoring non-Tox file</source>
<comment>popup title</comment>
<translation>Fichier non-Tox ignoré</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="200"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="224"/>
<source>Warning: you&apos;ve chosen a file that is not a Tox save file; ignoring.</source>
<comment>popup text</comment>
<translation>Attention: Vous avez sélectionné un fichier qui n&apos;est pas une sauvegarde Tox: il sera ignoré.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="206"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="230"/>
<source>Profile already exists</source>
<comment>import confirm title</comment>
<translation>Ce profil existe déjà</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="207"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="231"/>
<source>A profile named &quot;%1&quot; already exists. Do you want to erase it?</source>
<comment>import confirm text</comment>
<translation>Un profil appelé &quot;%1&quot; existe déjà. Voulez-vous le supprimer ?</translation>
@ -1040,27 +1091,27 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation>Votre status</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1089"/>
<location filename="../src/mainwindow.ui" line="1101"/>
<source>Add friends</source>
<translation>Ajouter des amis</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1115"/>
<location filename="../src/mainwindow.ui" line="1139"/>
<source>Create a group chat</source>
<translation>Creer un groupe</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1147"/>
<location filename="../src/mainwindow.ui" line="1174"/>
<source>View completed file transfers</source>
<translation>Voir les transfers de fichiers terminés</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1179"/>
<location filename="../src/mainwindow.ui" line="1206"/>
<source>Change your settings</source>
<translation>Changer les options</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1767"/>
<location filename="../src/mainwindow.ui" line="1794"/>
<source>Close</source>
<translation>Fermer</translation>
</message>
@ -1085,12 +1136,12 @@ Voulez-vous essayer un mot de passe différent?</translation>
<translation>Vie privée</translation>
</message>
<message>
<location filename="../src/widget/form/settings/privacyform.cpp" line="88"/>
<location filename="../src/widget/form/settings/privacyform.cpp" line="89"/>
<source>Encrypted log</source>
<translation>Historique chiffré</translation>
</message>
<message>
<location filename="../src/widget/form/settings/privacyform.cpp" line="89"/>
<location filename="../src/widget/form/settings/privacyform.cpp" line="90"/>
<source>You already have history log file encrypted with different password
Do you want to delete old history file?</source>
<translation>Vous avez déjà un historique chiffré avec un autre mot de passe
@ -1171,6 +1222,24 @@ Voulez vous supprimer l&apos;ancien historique?</translation>
<comment>Default message in Tox URI friend requests. Write something appropriate!</comment>
<translation>Je souhaiterais vous ajouter à mes contacts</translation>
</message>
<message>
<location filename="../src/autoupdate.cpp" line="431"/>
<source>Update</source>
<comment>The title of a message box</comment>
<translation>Mise à jour</translation>
</message>
<message>
<location filename="../src/autoupdate.cpp" line="432"/>
<source>An update is available, do you want to download it now ?
It will be installed when qTox restarts.</source>
<translation>Une mise à jour est disponible, voulez vous la télécharger maintenant ?
Elle sera installée au prochain démarrage de qTox</translation>
</message>
<message>
<location filename="../src/main.cpp" line="68"/>
<source>Tox URI to parse</source>
<translation>URI Tox à utiliser</translation>
</message>
</context>
<context>
<name>SetPasswordDialog</name>
@ -1292,150 +1361,154 @@ Voulez vous supprimer l&apos;ancien historique?</translation>
<translation type="vanished">occupé</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="73"/>
<location filename="../src/widget/widget.cpp" line="74"/>
<source>Online</source>
<translation>Connecté</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="76"/>
<location filename="../src/widget/widget.cpp" line="77"/>
<source>Away</source>
<translation>Indisponible</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="79"/>
<location filename="../src/widget/widget.cpp" line="80"/>
<source>Busy</source>
<translation>Occupé</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="82"/>
<location filename="../src/widget/widget.cpp" line="83"/>
<source>&amp;Quit</source>
<translation>&amp;Quitter</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="85"/>
<location filename="../src/widget/widget.cpp" line="86"/>
<source>Change status to:</source>
<translation>Changer le status en:</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="154"/>
<location filename="../src/widget/widget.cpp" line="155"/>
<source>Online</source>
<comment>Button to set your status to &apos;Online&apos;</comment>
<translation>Connecté</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="156"/>
<location filename="../src/widget/widget.cpp" line="157"/>
<source>Away</source>
<comment>Button to set your status to &apos;Away&apos;</comment>
<translation>Indisponible</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="158"/>
<location filename="../src/widget/widget.cpp" line="159"/>
<source>Busy</source>
<comment>Button to set your status to &apos;Busy&apos;</comment>
<translation>Occupé</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="382"/>
<location filename="../src/widget/widget.cpp" line="388"/>
<source>Choose a profile</source>
<translation>Choisir un profil</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="383"/>
<location filename="../src/widget/widget.cpp" line="389"/>
<source>Please choose which identity to use</source>
<translation>Merci de choisir l&apos;identité à utiliser</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="409"/>
<location filename="../src/widget/widget.cpp" line="415"/>
<source>Choose a profile picture</source>
<translation>Choisissez une image de profil</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="416"/>
<location filename="../src/widget/widget.cpp" line="423"/>
<location filename="../src/widget/widget.cpp" line="444"/>
<location filename="../src/widget/widget.cpp" line="422"/>
<location filename="../src/widget/widget.cpp" line="429"/>
<location filename="../src/widget/widget.cpp" line="450"/>
<source>Error</source>
<translation>Erreur</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="416"/>
<location filename="../src/widget/widget.cpp" line="422"/>
<source>Unable to open this file</source>
<translation>Impossible d&apos;ouvrir ce fichier</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="423"/>
<location filename="../src/widget/widget.cpp" line="429"/>
<source>Unable to read this image</source>
<translation>Impossible de lire cette image</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="444"/>
<location filename="../src/widget/widget.cpp" line="450"/>
<source>This image is too big</source>
<translation>Cette image est trop volumineuse</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="471"/>
<location filename="../src/widget/widget.cpp" line="477"/>
<source>Toxcore failed to start, the application will terminate after you close this message.</source>
<translation>Toxcore n&apos;as pas pu démarrer correctement, l&apos;application va quitter quand vous fermerez ce message.</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="480"/>
<location filename="../src/widget/widget.cpp" line="486"/>
<source>toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart.</source>
<comment>popup text</comment>
<translation>Toxcore n&apos;as pas pu démarrer avec ces paramètres de proxy, qTox ne peut pas continuer; merci de modifier vos paramètres et redémarrer.</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="514"/>
<location filename="../src/widget/widget.cpp" line="521"/>
<source>Add friend</source>
<translation>Ajouter un ami</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="526"/>
<location filename="../src/widget/widget.cpp" line="533"/>
<source>File transfers</source>
<translation>Transfers</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="551"/>
<location filename="../src/widget/widget.cpp" line="558"/>
<source>Settings</source>
<translation>Options</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="670"/>
<location filename="../src/widget/widget.cpp" line="656"/>
<source>Couldn&apos;t request friendship</source>
<translation>Impossible de demander en ami</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="684"/>
<source>away</source>
<comment>contact status</comment>
<translation>indisponnible</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="672"/>
<location filename="../src/widget/widget.cpp" line="686"/>
<source>busy</source>
<comment>contact status</comment>
<translation>occupé</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="674"/>
<location filename="../src/widget/widget.cpp" line="688"/>
<source>offline</source>
<comment>contact status</comment>
<translation>déconnecté</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="676"/>
<location filename="../src/widget/widget.cpp" line="690"/>
<source>online</source>
<comment>contact status</comment>
<translation>connecté</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="678"/>
<location filename="../src/widget/widget.cpp" line="693"/>
<source>%1 is now %2</source>
<comment>e.g. &quot;Dubslow is now online&quot;</comment>
<translation>%1 est maintenant %2</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="888"/>
<location filename="../src/widget/widget.cpp" line="935"/>
<source>&lt;Unknown&gt;</source>
<comment>Placeholder when we don&apos;t know someone&apos;s name in a group chat</comment>
<translation>&lt;Inconnu&gt;</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="1035"/>
<location filename="../src/widget/widget.cpp" line="1046"/>
<location filename="../src/widget/widget.cpp" line="1091"/>
<source>Message failed to send</source>
<translation>Le message n&apos;as pas pu être envoyé</translation>
</message>

View File

@ -44,9 +44,6 @@ QGroupBox
color: black;
background-color: white;
font: @bigBold;
border: 2px solid gray;
border-radius: 5px;
margin-top: 2ex; /* leave space at the top for the title */
}
QComboBox

View File

@ -338,17 +338,20 @@ Section Uninstall
Delete "$INSTDIR\${UninstLog}"
noLog:
Delete /REBOOTOK "$INSTDIR\uninstall.exe"
RMDir /r /REBOOTOK $INSTDIR\bin"
RMDir /r /REBOOTOK "$INSTDIR\bin"
RMDir /REBOOTOK "$INSTDIR"
Pop $R2
Pop $R1
Pop $R0
;Remove start menu entries
RMDir /r /REBOOTOK "$SMPROGRAMS\qTox"
;Remove registry keys
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
DeleteRegKey HKCR "Applications\qtox.exe"
DeleteRegKey HKCR ".tox"
DeleteRegKey HKCR "tox"
DeleteRegKey HKCR "toxsave"
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
DeleteRegKey HKCR "Applications\qtox.exe"
DeleteRegKey HKCR ".tox"
DeleteRegKey HKCR "tox"
DeleteRegKey HKCR "toxsave"
SectionEnd