From dfd1632b78b1ed20221ab84e3791e1f9ac168692 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 31 Jan 2021 22:50:20 +0300 Subject: [PATCH] import qt code, update paths in project and sources Signed-off-by: R4SAS --- .gitignore | 12 + .gitmodules | 3 + LICENSE | 27 + README.md | 3 + contrib/.gitignore | 2 + contrib/icons/128x128/website.i2pd.i2pd.png | Bin 0 -> 19680 bytes contrib/icons/16x16/website.i2pd.i2pd.png | Bin 0 -> 1379 bytes contrib/icons/22x22/website.i2pd.i2pd.png | Bin 0 -> 1770 bytes contrib/icons/24x24/website.i2pd.i2pd.png | Bin 0 -> 1944 bytes contrib/icons/256x256/website.i2pd.i2pd.png | Bin 0 -> 54469 bytes contrib/icons/32x32/website.i2pd.i2pd.png | Bin 0 -> 2890 bytes contrib/icons/48x48/website.i2pd.i2pd.png | Bin 0 -> 4910 bytes contrib/icons/512x512/website.i2pd.i2pd.png | Bin 0 -> 171666 bytes contrib/icons/64x64/website.i2pd.i2pd.png | Bin 0 -> 7273 bytes contrib/website.i2pd.i2pd.appdata.xml | 57 + contrib/website.i2pd.i2pd.desktop | 11 + i2pd_qt.pro | 184 + src/AboutDialog.cpp | 21 + src/AboutDialog.h | 22 + src/AboutDialog.ui | 194 + src/BuildDateTimeQt.h | 7 + src/ClientTunnelPane.cpp | 220 ++ src/ClientTunnelPane.h | 126 + src/DaemonQT.cpp | 195 + src/DaemonQT.h | 88 + src/DelayedSaveManager.cpp | 3 + src/DelayedSaveManager.h | 26 + src/DelayedSaveManagerImpl.cpp | 140 + src/DelayedSaveManagerImpl.h | 84 + src/I2pdQtTypes.h | 7 + src/I2pdQtUtil.cpp | 12 + src/I2pdQtUtil.h | 9 + src/MainWindowItems.cpp | 2 + src/MainWindowItems.h | 17 + src/Saver.cpp | 6 + src/Saver.h | 25 + src/SaverImpl.cpp | 81 + src/SaverImpl.h | 33 + src/ServerTunnelPane.cpp | 278 ++ src/ServerTunnelPane.h | 183 + src/SignatureTypeComboboxFactory.cpp | 2 + src/SignatureTypeComboboxFactory.h | 86 + src/TunnelConfig.cpp | 67 + src/TunnelConfig.h | 260 ++ src/TunnelPane.cpp | 405 ++ src/TunnelPane.h | 191 + src/TunnelsPageUpdateListener.h | 12 + src/generalsettingswidget.ui | 3810 +++++++++++++++++++ src/i2pd | 1 + src/i2pd.qrc | 6 + src/i2pd.rc | 32 + src/logviewermanager.cpp | 45 + src/logviewermanager.h | 130 + src/mainwindow.cpp | 1126 ++++++ src/mainwindow.h | 883 +++++ src/mainwindow.ui | 1053 +++++ src/pagewithbackbutton.cpp | 24 + src/pagewithbackbutton.h | 21 + src/resources/icons/mask.ico | Bin 0 -> 156564 bytes src/resources/images/icon.png | Bin 0 -> 8712 bytes src/routercommandswidget.ui | 127 + src/statusbuttons.ui | 163 + src/textbrowsertweaked1.cpp | 9 + src/textbrowsertweaked1.h | 26 + src/tunnelform.ui | 104 + src/widgetlock.cpp | 1 + src/widgetlock.h | 35 + src/widgetlockregistry.cpp | 2 + src/widgetlockregistry.h | 27 + 69 files changed, 10726 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 LICENSE create mode 100644 README.md create mode 100644 contrib/.gitignore create mode 100644 contrib/icons/128x128/website.i2pd.i2pd.png create mode 100644 contrib/icons/16x16/website.i2pd.i2pd.png create mode 100644 contrib/icons/22x22/website.i2pd.i2pd.png create mode 100644 contrib/icons/24x24/website.i2pd.i2pd.png create mode 100644 contrib/icons/256x256/website.i2pd.i2pd.png create mode 100644 contrib/icons/32x32/website.i2pd.i2pd.png create mode 100644 contrib/icons/48x48/website.i2pd.i2pd.png create mode 100644 contrib/icons/512x512/website.i2pd.i2pd.png create mode 100644 contrib/icons/64x64/website.i2pd.i2pd.png create mode 100644 contrib/website.i2pd.i2pd.appdata.xml create mode 100644 contrib/website.i2pd.i2pd.desktop create mode 100644 i2pd_qt.pro create mode 100644 src/AboutDialog.cpp create mode 100644 src/AboutDialog.h create mode 100644 src/AboutDialog.ui create mode 100644 src/BuildDateTimeQt.h create mode 100644 src/ClientTunnelPane.cpp create mode 100644 src/ClientTunnelPane.h create mode 100644 src/DaemonQT.cpp create mode 100644 src/DaemonQT.h create mode 100644 src/DelayedSaveManager.cpp create mode 100644 src/DelayedSaveManager.h create mode 100644 src/DelayedSaveManagerImpl.cpp create mode 100644 src/DelayedSaveManagerImpl.h create mode 100644 src/I2pdQtTypes.h create mode 100644 src/I2pdQtUtil.cpp create mode 100644 src/I2pdQtUtil.h create mode 100644 src/MainWindowItems.cpp create mode 100644 src/MainWindowItems.h create mode 100644 src/Saver.cpp create mode 100644 src/Saver.h create mode 100644 src/SaverImpl.cpp create mode 100644 src/SaverImpl.h create mode 100644 src/ServerTunnelPane.cpp create mode 100644 src/ServerTunnelPane.h create mode 100644 src/SignatureTypeComboboxFactory.cpp create mode 100644 src/SignatureTypeComboboxFactory.h create mode 100644 src/TunnelConfig.cpp create mode 100644 src/TunnelConfig.h create mode 100644 src/TunnelPane.cpp create mode 100644 src/TunnelPane.h create mode 100644 src/TunnelsPageUpdateListener.h create mode 100644 src/generalsettingswidget.ui create mode 160000 src/i2pd create mode 100644 src/i2pd.qrc create mode 100644 src/i2pd.rc create mode 100644 src/logviewermanager.cpp create mode 100644 src/logviewermanager.h create mode 100644 src/mainwindow.cpp create mode 100644 src/mainwindow.h create mode 100644 src/mainwindow.ui create mode 100644 src/pagewithbackbutton.cpp create mode 100644 src/pagewithbackbutton.h create mode 100644 src/resources/icons/mask.ico create mode 100644 src/resources/images/icon.png create mode 100644 src/routercommandswidget.ui create mode 100644 src/statusbuttons.ui create mode 100644 src/textbrowsertweaked1.cpp create mode 100644 src/textbrowsertweaked1.h create mode 100644 src/tunnelform.ui create mode 100644 src/widgetlock.cpp create mode 100644 src/widgetlock.h create mode 100644 src/widgetlockregistry.cpp create mode 100644 src/widgetlockregistry.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..75fcca5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +i2pd_qt.pro.user* +moc_* +ui_* +qrc_* +i2pd_qt +Makefile* +*.stash +object_script.* +i2pd_qt_plugin_import.cpp +i2pd_qt.pro.autosave* +/debug +/release diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..051e5c5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/i2pd"] + path = src/i2pd + url = https://github.com/PurpleI2P/i2pd.git diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9a1e452 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013-2020, The PurpleI2P Project + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..94186ec --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Build Requirements + + * Qt 5 is necessary (because Qt4 lacks QtWidgets/ folder) diff --git a/contrib/.gitignore b/contrib/.gitignore new file mode 100644 index 0000000..dde94bc --- /dev/null +++ b/contrib/.gitignore @@ -0,0 +1,2 @@ +*.tmp.xml + diff --git a/contrib/icons/128x128/website.i2pd.i2pd.png b/contrib/icons/128x128/website.i2pd.i2pd.png new file mode 100644 index 0000000000000000000000000000000000000000..ee5400c4e88c8e98604275f8f9e3da821881ac01 GIT binary patch literal 19680 zcmV))K#ISKP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x00(qQO+^Rd1{x1H47E}DPyhf+wRBRj;mc?*%Y5gpv@FFC~E=CEpN82;`fD6cbV)2_X~*Y%t9j+qelA zSzWTaw9>A&*O{H2UT!_-_s6W7t?pI9A0B^ft-Le$o_pTszUMt}JHT)8Tl^Mti?_Y& zTL6I8h9$v>zpgtRXq`8&<7%zBY31b}+Ur0r_W<5(xbv>hVx;fuQ1yk?k;udsJKBo( zYbq`5+aLUo@u`k)d9`A3%g$FW_b`uvUhVGt8Q#g3!QAENs_g;Hd{{0mpr|zD6 z^Yhl;kos6+W?<2p)$ZjU;z_<9px1 z-8bKSNk*Xs3uuo1uX3nQQXYTY$A0hka%6BoGPi8@Y?1{3;U|B|FZV>9gf|5NZocM5 z^z>fkU)-JizqK`mKWJ&So7i*6e6X1N)USZgxBxITdAVon zWV|Viz(^E!a}y3GHZ?TR&0BXiU0Igj33yXzfU$86L4Ww*v(J{cC*tgmVo5%*b63Sb>^;!7 z`~Exb!xPV4oZap=VBCV?4h>T|^WS@Rjn8b~ zw)=8V&l&Ni&;W@*R_Suv?r)ZAyT)03#x#wh-|NK#zAft9|+P))VHnbzDJ5kqo; z8PklDJfCAPckO(DJZHieD0Ldi+OH_i!vCv_9o2%M0$|{rz;aWtFt}b1nBVT%lPvZ0 zJbAfi=&U$L4Zu+j8{9zwfdK6;kOlC)%R2Y~4`7G5SDHtf?`l_?76_myxW#dzN*RGj zb9SGOt|)vFOYE!m+z6}g3mR#^Ruv;+`R(T5AaJ>flG{HZdeaXM^p6eRe%nnTr0cTI z&$-~N1o-$zeuamB`d(5UTGG-`+j9#j*GGqkUs71bzCA-=mviv`yavNAHMVH=ch`zh z-Czb!^ZY2Ua5ADv-mvZU9SisqHHuQH=+7LCzEfn)pV5StPLX&)NLj^j4sbADbOv)= z8vjO3tMQ`ltHpEAzj!&P=A3a>0;FdC6%AE0_3h0we_I*J-MgU65&8#=S6|*pKLLDe z7v~?oJnNhajOM0Do2T*mCb4#jPF0?C(UVg>@V7uyk33UjsyF81Nv{AXVSjAXNteAj9$nhd5*3sQdzqqWOky z@zxLcNM+62RuH4(K?RHcSeII(0+k2=ay*JoxalTXiT6COc++1U>YtfexoW|spN}_y zvl3uxDhu0kat`B#d+#%`V6lU#7!jtY3(cYE;qb!MlyLsZOFQTpg6TUGs6}*DlURGT zSI{UpN5&~6O~D!b(a1WW^8By+=@Fp96F~D4C|jNh-Aj!2uY2gC2UMX-A+MP#&Iz|! z9tEdo4^`uTH#!nOa`p91ci_KBXx}9XOz!M#oRh(ZYOC;n%v;eGYF=C~Mwe(rC7hSnX9K32=f!b8 z$sJQT`wrmh8@sT7PdDo8T2^zj>0dS4b)PJRC2|H2qU9#IiNn7RMeTpsw`U+eIys16 zedoYM63wN-g}H(WaNQrKKuf-?Ka%@*oAy3jv`0*EfKmk>sa5unTgVq;iICg z1OVWT#^t?&g0FP^RH~99ch<>OHRatn0pl)mD3~t6%(YdkfW(=vGq1A>(fS@zTRVIm zD>nU$E_B@_3H~$Ah3)21bPw$l)x_Vu=Y3ZlzUQ9nFQ!~B87?>$@bkX~4iEhk26{6w z)sy{d(d}7hIWru*{01pvg!{y$Exgq9<=D9S#n$%fdP)LVc1_C#4_2{7MDmplQ8&28 zOLPGQAOvu^OLA^8;fT(3%t_!({>jcoL9|~JquZWqx{(-7U)6<HYum2WNmVyRXvh!D#`}0V9Ft>(WX{fH^G@!R-@omB6qq+d3L9&$5v`WL z*M+u~l&ZjKUVY9vI0rYJxa$amj|U>ocP0mm=HY|=mry(xA9F$gA3lPrP=^%^yFW59 z@Qmfo;OM-TwE=-wY7IEM)fAiM|;S0E?*wm$k(ptH?{P)gy-FYqb`1|yqBEa+&At6u; z9QVx<5SZLzE^)I^;NmrD06+g&9SpIjlG;sws*?6QMd~ADHkx;aY2l_5V-6kumF!DD z@$!$8?7+@}ODL90hdCv{%j?wSAxVJS?9X)S<*~$2G0N)326DU?dzzPU> zCn!Dy;C*u`f%C_l<^&Q#uxR-Lthrt9ef&Gq-!-i9MFQ>c&#nMRKLtuaJaQ9-<=&Q< z>iLKEw#LtV|Di_@-G0YfJooJS*Im~dv%vChwa4#SqzfuQW;Xz{f4Gb@mvaXSj_LKv zMlYUkm?n|O=Es_&5m-)tQH7*#+BAs)FE++ug6lLw7Oi|2p#xo6i8u3PsEZoT!+W1kH0 zR(y)Q2VV_6T<@cvTKXC{ZF%lzO+p=@7QtKIwgOK)mO_;oUPRpHPboru4LPbV&IC^2 z@Dd!152+sW@k0mF#m|2B6L|2!e>?ee)e;~HGG@%mdK!&}7wpRF{B^QPdpAv2nAyjra_p@uys=mRrR?b3iCgq(WaG@C>-Q$S)v>SgxhYC zIb?c6L!Eb@rYU9NR{)Seq@twPsMQT>L0DcVS1$|co|Rtc^D2aZKOhD)nMi^F3Xup9 zi7@dpY?tt&1Gi{$8C(Y}`&jHR|VzXFY@jC0<*Gie~zhn>; zqEy(SmKqja5tT!CR`bZhDo?n@OLf1OYDA{utQMMm9+a1oqt|p{Bj*;7bTW2^=Myn! zW-Q4v6Sm+Su_^1z+4-?paXN2_u1P2{z=%Z{cPS;D%7WlfR|tEem6?q5nV{di^Zg$z z36jFGd5cvm2xcPyWD-X%SXLLUF2EBKaA?n+Gc`3Y{lGLPZW3vr8l0R`3sWk>D|O0Q z(|lhpJvh_c8u~}awzFenG0gWgBPSN63c*(^lGn$1Ip0OoohGz_c@CjyRJO36|bHVaGRSX|c!EX-_7ROhV-r=EKCRVAu^{*(ruqvhn}^ z;`{jCPlm|e{Xd@i&UeYdw)VmehDrSU_XjsgnzpsQtsQ$dU- z0KL5hR95zZ2^SSCIW~Q>QIA9NL)O&){j^dY=?2M_b?lNC@JQCVuy`kEmSohL=YWL^67PfpMf5h~H!}FTG zJSJJ3LI~2aF@u7Hi-0!*ueihFsbN8x{s|&iB9Ec!Mskvm=uPn%g%3 zQgX(%)E3HvO9eqEr*p@Z_v;{%;Dv4T=4@d~tCsz4J8irrAo|2pZ377*#O1EoZ{*sk z*yb0ha!$IRgM-RrxMuz!K6{sr8#@CaAn2VkuxmJvy<Km{mgMYoDhPPlOqF6rbMhHr}8}40rKJ|WU@=k1&{hGVr6SSk+4dlmh!9CgEgCb? z3Q8%JL`({C%t%RO+#(nU6e5FwW3MreG3tjXcxHFyXY%)RFq%PEV=w;nPA?>p;Ni{F zm`Gc=WkC@4Evdk&W*-*Sd$6RzgB2}abW~}GXDqyMD1*Goa80`(9Z^*oiklsM8%L^( zDZ5ja<+^Z1#8X`z<#}_4L|VYtCBSB~z@aUdYNpQ*mn^vbZ@*rKPu%ieR7L;!7SZbd zACK78OzGKTQ5@g|CZ9k+KY;7oH8fWXP-GyL;~1L~V8tQ`mcm${pGI10hDaow+4$#R z+=V~5AD_F&L`Rj1N48F*ty07N%PL?w3_X)2Or}kkHis$^R0U+ruhJ0lNjMxU;jx`F zhV}p7@7; zJoA&CmulM2ic6Z^aN9jsp|@{Oz)W=fqlTp)R>Tm+nch~;!H9)ms0Saowt#z=1Q7H{ z$IPpE+Qi1b0-o7nVb54Kz~=${%r1Y(d`K=sMTL$q1-Qk zafcNx2l*05Y1HPKJuXr^MakS?VxqsH*-mG(gbg0DFQo`xhs%)OvItex)3=D$;%|F} z`AvkJ+O|LHP!*Ixy!YC1eB{OmQUw>!9ZVx#bkGt}aBaIE6}pJM<9U4Zr4qIuX$H4z z%f-8=xF+WuoS3K#@5LAH2lkH_;ZsH2yEuf$cPBBLG;!;KAi8UHcoYF51sDhN7Q>NP z3F{AMP_!5xSP@2*U&6OviJ>+qV_BmIfAzS5BO^-yrk$XH$ZRE%3&t%lZkBAGoMI%i z-(~6NA!oNro?K5dGLx4};HiC=UK*Fo1~`h&ZUJ0~PunG}LqNq+N;GmRUp?mlsDYYD zKmPa@9hxNI;jM9S4s=8{9Els)+@C|#FQL2EgRU9@Q~4Oi(g0jP`0L!xWxYY=G2Fi* z36Bg+rfs}^MHo-+O(BtY@O#%(p{rH{r4)&RjsBQ{>4F2FBA_L#U}2pH1=Gbd`_rfn z$hfN2hvyHbQR$Q6Rc-7U5x|`wPBcQx1}z085*Mf{iX;@05bh8Vx`{CVO|GFYlF~lK z&5@iCUz`x4@wrpGy78rdnI(%Xy~dHku1eAoOHlkA5Qc-at<(>#r%eT+`ml0w!u8^ zSscQlsS=LF4gB6UQB(ya#B(;D+?&F42htdtF>z?Jgl&U400fO;8J#s6WRc>@JxMf$ zRV=LcKp;S4g@nxmdE|>x0K%!3p;-?y2O$Cks*55CLLn)t0DSQ)NsLeJPv$eELtqul1ggB|6XmTPqcd3BmB#88FJ9@(qAE~U zw~h-)0zrFJgUdOd+n+*RNI`3*itbtoC1)CgGey|84+K(K_@snj@G$=91|XiZ5!3`U zMN~YqFNFtIgwYaF(Hkq_k*($Ak9!wa;HItsRyO&dD-`Q`(y$zk=7@r(umXV+JiRZ4 zUgDW}LD&5|U9Qjti4UzKP@v&ci&Q|`IeEqJQ+z)(*2 zmr_CIb#nF_>veF&5#Z%tZ$oT6X9Pn3P;hPSR*6*jPM)xG#D$A9Sld~|!a5Bb`m*S( z)=(c(jv0X*Kyz3@!DM*3H-mXm4OM;_i|SQ)v<$|xGsv4ZI4vOLAH)Z*H?g>0$Hu-a z?pPSY%ZD>)3@f;4egKE2ig9V7s{Ilqfj|)n8pA58d@?p1$)ce`ML-kL zP@y1iF>L6|V1Bg*zbaxPQ^NLs34{gDDSMb4`v-&&fe6GSO0=Se^58YZ^<2*^HChs~ zX*pn}ex8T>$d}(F1OR|{y>AbuQ@wGkD7OndxKtp@NpV6#08Ud_-I_yJt%i+9a#&pN zLBw}*)+ZqZ&0z%t(*}AbOX#X88*mG1RV=D!s0t;~S(n1Q*HGNHAcz+aWf0H=RC*=6 zI#j?rS4NO3I(TGj0?Qh`xNA`eA|Iq-|Gy3-AWg z&a+}?=S@gwK^p652u`s&lM&*F2jVk;&Vk(*jQ}6}zg>9i>fyW^jQ_~8;D)8+MF|6;+;I{4%1WK{6&V#NR4U7Y_ zNHLT!&>Jh^J*z9Rr9X$x8V!m>@$i;uv{tIPy}N9{o!W~}P#us@`kg8gynRIkjF-O? z@`&*3Hj<_Ta=~Gia=@Gtfy*Q;OVq#2V$u1QGk$k^a{POiF#ZHY#JLU3MTr7cXI?~O z_00T`|IoiLS=9UE<;#wIqide96u1MxTQ3>`Ze08o_-kgMh0{yxFS^Py4Zc4%oaZ=nG62CCR~5ZRo4fVAZl>OC*GJGgsI|9@~Y*r zPhPz`{YO5pU48S7rOtGQY6k{-_HuPAlPV>A;O~EzNnr^Sd*`;-xxb1be&~Kn_V#3n ztKTBgir|S`C{9dx^*FBUP_b{Uh=uh!0@~3xi-U8HZG(AiAIza4q@X>jK^6&qwJ!xt zCa4K05CsCu;rQk586@&H9#|2Iy>*-elme-ujdlB7q;gSEBAq}1GFxiqz~vSgv*2RhIzEA($KC0g-nGXC}l591|m=pbd5FMdW$Kl8sn7_ zS9s|K}u|inKugPf`b(Jg=e?`qla^7ZQTS( z%kRie#viv?^~WUY7szbYjzGK^PfAD?Y={DdeQG%!Ur?79dh^l~$p&0|F&GFu=qL|89I1(@6?JFX9dS43HwENK(RpBs>M9x8P ztc3n}3DbES4g(|#bl2%vsfzEHSoQgj$r3bF5k=1{R zHl|)O$9(2TA05Yo?>^hCzm5R&%&Dp53p;iyciwqtA>7+1vECyzu5l^cB{nV%$vzm| zvS)avH0>lu61ntXo|=7`L%A(^R_H+$CY=g90}~7vP&^}wE>e>XMNvsTVi~d9MC$1T zFTVkVDaaIc^uZv;F>l+h7txOf#CWMKL!&9HXg}hWX6K73TUcOu&~jK3ZI04 zLd&)X2rR}R5CY*e8Rn+L;BXO?5R~i~3}?i2kQkOUa|cJ^6+-z?MMZF;uC8V#TItOn z=-X+lvPNpF>*RPm?MqHiRix6HXtCf%ylQoa$&^*xR@-D+StF8wU!-0_i2?!^XOSYI_g^xs%!{o>iD~w8Va|jvO;!nM16R4 zJmJqJxsfV7V^pLMq;OZ5>)GbufOi5hhSz>p%{l{-KSj z8Dcw_+$Ac;V|DeBr**G3@cs|}VSeAfJ^VlZ^*_%z7o3j+sKvc+UnXtdwAbrZYpNVm zSZx~83K^AaC=bq4glIq@J}MB2bMC-!rwRu8pQh@>S0h!i9mRs~_V=Azmn>3+&tT05 zCvjk14fXm5gARA>^gv^7yyxq{)g%}y`EP6^b$`$;cdYGDn*BbiAJfA{W{|9#XK{DN z8MES3(=0VKLo)l)JhQ`w+iPj|uw&RMNl^@DyUb0WI$0tV1~j@H4v8(4oCV+3>AcmH ziX5C1hCG_vE zB?K#5yja`e$4tS&p~(_PlO|$W8%ygo^iJilu{VW76L}=_HVlWu;YW>8hL%bhpS`;c zZ(CV?Y#VqYC;^^5kir)qnTBF0(}v&q%b9TYyFNp=1`l6&%e41@0{HnOAU9mQOxdyZ za5J+4i@58*U8YsnNT_U4gos9=a*OAf!H(>9g`t0yJ=4E1v))|es%gCX+*t^4))6cZ z67fi(t_I<^bkL^XU#!ksR4>)Y0w^!HP@^2+a5+cb&68<2HHXOK7js5cY@&c|?SCX*M_m ztUH*(zOe#YBND#1eiYjWb1)qOK_H;CY>08r!I*<3^*TOxZyRpx3WL(qcM^GY`!rs9 zrV)F`yG5ai~V`p~+O&ZV_da`LTziT2B-=1`{j>DXKAN6=Os$jN> zA|V7s6%<6oAgPn8oqrFN+V_1dDW?jsj!*V$^iQ`|N8Njxo0*D|&k_41<6bKk& zkg1Ei7FFQO56r_=?V&Sz_Z-HsrO$vfUXL15Nh3n2TH(@i3wAQ$OC3V-jUQZm44 z0!H4p=5_lg+Pl?liOj@HB`bBvWm%CiH>A+2sDR)K=F;Y1)%d`Q+dZ+tgZa}YD4vri z(3-Tsk}m7KuVeB+U+=~#CwVx_@)Z(8F%r=)2Veu(k z+aW@cDE@2R5Wcg14C@Ze;ORZnc=2Eodq%RDN|oR^E<{RTI2_Fp6&+P7)*VbE>XQ)l zmmN6*A&B}!{NmLZez7Y7K@^X@*^F_x%tc*5z(;Rxz^CqNMQhY^<`hp3Sgwl~_Zg6; z>*3=%BqH*N7z~SCT4oqlY(`4=z@EGA>Qmzd^dC;K#+JI2>|y&{8hg=pl06Q~2?Sc5 z$SRlFCRs8)R)~jdvxAzhxS>Ebve}b6sGOH8INp;06qqGX>CkjBxiR6U(J7gR0)yWRYSUi zl#I@jldJ^^>H_tGKtRz=qqVAp>)HdTt5C6XD2<7<0|x?14v;9g7)lt}Kc2^tSRPZ! zBET7L>6x)Ir3WD67wD(?@eUhX4{5JfYCB*@#PDM1y}$I0BUF| z;Uu@l-PE3>lhMI>gP(d-kw_fmcp2ac0gqWi%=U^P1QHS95p+bv5Nf5U)F{>HZBj#| zLuzVlq#-TkBuSC#5UC2wb>Y$CSlyp3ScVZpebA~E&S!~B$^`%HXcr5_iz@PL{J}+a9ei>pSrUdAG)Cd9o61*ZU;jE zOk^!Qx2uGTTpc`AJr?g1An=G741@9c*;1h={m%4|XT%4)FehfgF{IFEiNv%%!ci?cU><+~3_k8Lp|$&Qqk?Y~}JoKCFuu9t>hx287|3t~Q3ICT3nr zIGM4$TdYq@hFQ!sOjLj5bxwGz}6R5{HFp(@lARLte4PlRjpe|y^P#z2GJWwTy#;}5St*ODs zZfV53udYRBtq+nYl&gi#(VI&E^u`Q4vDX66NvM;;$H_xD5sAn{)L-qotTnkav+M83 zAIE+ryaHT=Y_Rw=Fg5{R)2!u!EmM2Asl4bqoK{864=r7sf7{9x`THtD_M+*&!QI#1 zw;}PyqJcR8y@04n#S~BPPVmg8X*+3}u2ruQ)vr;Nob4@oZJpiG|IIl^Q1F1cS&X{{ zKnQ>#h1IPN8p0|#2O7c}u9;VXh*w0(v{5u|FxLU)46?ux^@+HCUI=erQw@hv=!$@v zpn`p)MJ#IYU|EwNH!cWcS#tmppA3P}a)u%~zd#Em96N@JSa&dpg2B)t`Jm3`IFyTB zKolw=K)v-Qw?qHyJhi2URpv6CSs;Gy_cyZnE?`Cz(e$kXqAck!;~CbOlw zis`FX8m)r^Wa{DXt=cjtl|gpW!iV|S+=s}g_K(%cUrZEsKR1vc|4_Hmc1OG17zzm9 zGep@=&kO>JrCKA>g+BDyDHKf|eendYYWD*GT*grwRPpiKTJW}&HRy}wF_ku9+6+OD zgoX+gZBY+=ei`3>Y3k@@akRgjK+9Ufark)){X`AnFplw*4cDne5;n%HB)T;3Y{wCD ztcI{c2nx&O&iiwu*t=8vp z~c;JAR;PwkhCWe zV{f&WGBN21y`r39x-2k7}QUs(_5WqXjIi z_rR|SvlDf8VW0Rp&Ux7ri1LzCFkSp=pMfJ2HQ?~Ub>e81!k~oWL|X{p2nZfY;Iut! z76vAgu^y@k;LgP>Ba_4?BxWK-MJx)Gx=S6K`(Av}J9?-wy2#|R( zFBA?WXy%1+D?XB81s~@;q8%jyX7e`Bayd=_h02HuD&kfgB{_rZ+I0l<gTm%kCK zmhW&!#-oS#?#2EWUeNaR^j18idFQRmWWQ-&yo?|VfB|kd*|}^qziTu(^>V^Vk7eDQ zhjU(`QB{$NJezQH%H|>ENt^vsBPt?-j$u27jwYbBQhl92{%FDBYQEk4 zJ_%8uj6EX-EUZ600gf&c(>VtRCrj8loWszx2}Pm^Xd-fkgJ0}QqN`R%NSDwXE8-Wg zDlm;&5F)^27DBv)8nNOOs*Vte2=EfUD#uFN4ypI$NK7&F#r#DQ#C}Xn=8?%x+KFVk zZ)!TbDHc!k4G#7=$yEFjq=Y2^Oo6lauvF@BcIP;Yub;M(gDEGcGO&Mi!a{>XX{4#cr7SLT=CcsJem~A^d zmNN0oz7$?Kl)+@$fGzbAPXlGAR3UdYq)T12{?Xz030aU4A1OKfpda87KU)c`~X(B_|RFSqi3>+@r;eS z3I&HIidf$4g(6e@?9~Dejn#uNeRkOpVK@oQll;ea1Fr)i@KIfL1=f%urLFC;s;Oaf zZWC_K1(!Z4bavx!Qzw(QvU^8a?By9Zvu}oFEQ47g8KPIE5+x{a$xd`CfdDcjj9F=n z+0z(KnrIFy@T=v=a2dz;!5r50WN=GYu7%ibOD#u~F%jFrGHCs@aEZ$-&QGbug7^M7d3E zc^$Hufm+H@A^6IKevP$50Ek3{PLycU%&<+)u2)vxbCor5XzWc+fTLglI5=}zE^TKI zjf>MSO*_eLGc1!UGQ&$j{VI_~k%-5NY&bYX2(VlrF2>;18TO48%jsKb6E7XkVE1SN zcPftKS?fW*svUrjiVEdx{g~v zWhD0Z?(glr)MB_&P7mj9z)p>iO}#MbiEkd}lU=oLQ9?dR2+O`cGib%1j-U9-lXfecd z4u)q;2&GJTnMY7IA%hEhK@UW=RE}*_T4dBSI7i4vbsK6{|oY;zUme zBO;Q_f%}@4HYYvwtY&Ca8fq6fZGSXF(z{kxE*#%Hvip)v{N>XCuSE{PmjP~bC#Mu9 zCrEtTq%-qu+)eIJvQ#eb7Ins$CQ(UJh)e`m#s2&RZeOb5&czi7X$0AViJ&eb;!}=g z1q0=*g&l)A)C6R-R;nnNE?());mN&8Y#+=ck#}%?hab%m4M3SUro-?b>xOV(ynxT# z-HJ+|1c8<_k~Z{Z(ORh@8j$eNMib-l22ie^WQ}qFDQnbq+yoB@KB^G;6wAQu=_*tP z;iM)l+CON;Eyu>ui5+(oBfpydoq9h(unmbU6ofsw!Eh5Ew7U*L#kr$&_(%`~t7Vl}Ui3 z7zK(bz{;6ci5pXs#rV!#p!ifwn;G4m>0gz0LgA^LA88{+mNshWto5Qgpx}v}F+9IN zfl9xE+Mo()Hj#5fUlu!u3ve07TbG5gyvYlnLLtxgpQNOmW%Sc+llbb>L%4l$H9mM< z4aC{P0D%x3o-AQ##=s4oK|Hg+fK7+00XOuTJqs^~m{}o}bBDg1Rx&>wH7CWalWz`C zuliaC5x}8PkrPfMGfsM{uQ0ToguyQ4^waajl}&(IaDE>i{vpAtH7#;J>s+79NFNpW z{G~p5p+pfS{fRU*C5y%NI%VOQd zDq>Y@5Vp(lz4fEm*qeeXQ*_mM&=gj&YqW@gX##H7n%-U`}?xd zyMKIth8On4teL3H#g45tJh|ZKpD)sZixg+_gl;?_XO1O+Mb!QlP-T z@gjz13|!Uj$D>qqgy{_SD88ePX)K> zlNw#L$RoE%B2@@E(K&RK1k8i+YzAI6i^cU`fRxwl`L!NY2X*WmH87l&q1G)#-1Va` zMd4|`4z?7+o?S7dCIb-Q!Tj1Z{^Zv3j)3vw4jjkjczRz7tyLOq20XG+f>CM&g>cHy zCLsW0Cbtpa@U<5wxBjfJmVf`tIqW>N1DSLtX+_AZGo@ru=gPvU7#7R-;Y21PcR2G; zo9W(x%*bwtz}#gLz8+T`0j|5bTe6Do!s!Y7<1lMJ=M}nd^2uF(MGPE&?nKbZr(W&=)IV$8a7ubq4VGs|D;HYyf3JoVpeL(eC3GGg)jyA~(75p-<&b5~H0n zbF6~zPM2~GA>!|<5CXHYEJ9RBN`fV=5pD9NN+nb*7^RCg-&X_yKJ?*tW5L2s;@C#> z!e%`oN`w-Mizr;{6a?)7QmR^H0m0e;x9N(*X*NRwC42nUEvC6u@on6}d!{-E|9 zL+evJk0&L}F)k|s-tvxX@b35CL4Nhry2z2k<8RB(2!BDX<_~&>h0VIuAP7{(*$#O+ zY0^1BxEE7d6L~w16;0*5Kh8M>N-@7$L0yG`w3&s?DI_6_sGdeggMs(lpy8e+A;{uu zgG(IShYC0_QNr3zKOWvxK+i}EDEFV#4C+*1++r4wZ^+vd>tURtE+7P0f*H@*g-OX3 zuWgX3!vYaN2?b+ZNw}%uAH|>A98~?xur5xUm`hH8AN~9){PfY^!C(KAhirOfqWYy@ z@42U#(Lc}4+K=dT;X;qxDocWglVknk&LdBYlsj^P2QWC3f+%LNxZVR{R)L6=ptVxL znpOer)p>N*TUfhL!~<7(vAo#>fxf=vi?Oo$@2pXAXwt&Zwg%u@jW}Jy>yy6AEoLM3 ziXl$C!cJ8fVgRzNqa+l^Y?tdn_}4_mu*ATj5J`+VGsPiy>bW5C6>@d~7Xz1!0Dto7 zcjCXk^(B1zQ$N-NzJo1W*3Y~rGc9~paGE}%k1s z*CA6c@xbH;D|Kp9&NXZVm5`edGQ*NX7c~gcc8w}T07aG+G0ju!qhfe$$~eQxWp4l% zjR1f6*;ah)Q;V?c;IP=((Be6?e{#Y9e&?Cn3MtQrja=Z*h~4;3opvqI#b!+w0_051 zqt6XT`}vel{dAe-6f85@J3Wz&2B_Xvd2)s_o6YMxR?~kPc~SzzayI^JeLSuu=chld1BZI{opm4g$2frEo_n>(yv17?xIm^Pi%FemvzQFeD1 z?8HHnO^@qdKAwy*Bbh0$wYTyQV<-6uQg)$rCFxq)nwgIu{JIyS$Z_NR5M0Kwp)U(X zqIh*UkL8VCguP;Uw?%-7w1r2uCNfVQ$o8Fr84@#9yMlUs+1|CV*s|KjEhAR?uL#26O|AtFF1b2*>QuVaM50=NOfi?S@{tx_)KuzcQf%)FwLyw{7gRWx(S zr0EI@+#6p8JNPAF;zz)a=gUkwD*Q8{c3}<7{W%Ce_4-z^VM#~~a?Z;}TO+CvFuWMp zGm7sWjsf17LltwzVsvJ@!1kvK{CSJW&vM-}ZWT)`K6L!e)x9b{`lV}QU;6Nq&ziZZ zn-sBHKURZq5@z3j?q+S*%(k>#eNMvIapy~DTilBD%s~GXOKzBP(+g!TiV738YFdE< z!*eVA(-PqA_qKsU8|mv+`c|(g)rTT3dG0w+P7uT&$hW!QT=U63JUAcd9|ZpMRbb#b zkkLbcX@E!-Ao=04|IV>N>=Hl;xS|3~1($>1^>-5X_&-JXFNgB@Y)jeCUC02*6UN|_ zfOVbc|3I8`_`(6O1|eLN4!mu?+~gNPj~^>e2m;)LWu%i&6e`%dneET+aVGvzBI;ya zb!Bqig63o@o#9(IZ+zXgEB(M9-S>T7-=Mv0(d4kp3SA=goFW)Nz~O+y&Zrv6=B#r+ z->-k~0087iJmarS3#s2J=dy@$mFxv99hl=Rky8?&cc=zXYKOM(H2)@FRK|loyYk>6 z_4!;O@{{UAoIkn>c=R>%ex{o+0HxU-j5!AM?B|&G;KgxlR5nFXlN2${+1eIbcU`qy zNf};ub~G=zMI1B-w#R7VuUR&?ExgQ&f!zl&(0lN-*M9c-y=b3T3)N!}8QIKM+s)3C zs8=}E5G@4UKptK%l$$x-DgpG$D!r^*_@aZAZ) zz?Thrqv!Puha38k-<6%pDA_#@ccN6F_F!=es#k)MpS$iNz!|oInZi#2fRD$H*DsrM z?}(aHG|X#6p`KCicJ=;+Qrk_na@A}!Vb&JqoLk%`d(6Y5uQ~_6G@-6iTCcSbH*yTWQ@#muQ{A6EkoL2e-IQ_L_a;+wB8i z8sQT^qo&}VkMIHDbASFV)YSOk^6Ur%W7OpaIZ4F;D0?lrOGGQd$}Yq6y2p}*H$&5I z7NweeWWm}@^^#TjFI3KNUlx6Yb2?{l8Upwtex&?`Xq6TE^lD}ClCT&AaMZ;_ zU~r4< zdI30ovUi@9u+um=w8`A_SN-{s?~6<@%>0ELRH{ct`=W}X%L|7cRxH-nKIR^#d88?fqr9Hbh8@oR{x~&wQ>h93s%^}*-TWAc zX@WDtPs-TgaCpHGWitNr57b=19da-YZo4jFci(S9^Kzca2uVP8i7>aBLBG)isJ17FXO+0%^Q*N*l?suL1`aV{$DLP7JJ)S-_kVI!oq8POFms3Bcn$tN+g$wL z9}Phi#T2Ek4V-L8a1Ic`$|h3%>DG4Nd0+nze`f%>tiJE*r}ZsA`LSmF@Q1#UgNO8= z0l!mFl(`kz-0G7{2wDX&2TG+`@w=;~MSppXzNFbhHO>iv%^cEijU;#5hkkm<9Q<0Q zm^(Dr_g{%mVzS{!*P=N8VGmi@M9J~|K$lr4xVxXp^UWVz*xef6wDAJ^=;J!l+%UdK zk@?MpibD{B&x6~ALx=aw>2q8u)xqZlIV8h!El;%_{lIFu`}0?8i|RG1a}JJ_lV%6Z zfu8;B$bSxzu^%sLoS)cnXl{?>Z1@l`{hh5Kl;j=eSe5pxqe1R~gTEqnmDF4Bm{FoQ-#v2x%>IUBY7yK!M38_q3fAzZn`}rGhoj zRN-L6H?O%^^ZBdPCGVQAG-+8@aQp1x;U0VNCqrcFp|n5M3rlh@wq=t@$`BwxQ&f^C z^w}_OlS#e6&i~tv<0q<+D@zujnL=}cdY z(uI@&UL%m%Y-9l7+~hH(@=i=nFDD)Io@$7MQ_H;`8t5PJ z1>~6LLjic}4%q#V_uFGXm?}=c1jc7z;;;%%}THDm%s<++D=#Rc94)2*5`fN%_ zJX6e;kxh zKm6pqQYcV-&)s)s-*Vqu3Za#24E3g4OKR;rrxz6~f7MpEG6sNMf@S`!xF+yUFvdNU z%33+qop6U4;9_Ao7VhA899Du+IC1GM{L`t=_G7=7RzV3PdP%h*9 zSx~(yPVbJdGSK&sm`9jZg1gJzZTBzTCq+CtNX0Ky^(8 z^2NRGSUmj5FMjFRhYsmi*|v~4aM1VM=tSkqn(|ZU!1nEzdzb(KK^8z36B6K+ewPsu zA~-mM#bQIER(kQSu1OxBnd9``i-aqN0I$6A{OnH)62pUy|NZjD=|=#M1^ihFcm=>0 zFZU3Sp|+|HP3;-FcQQ~(9Z4b}u-v@Mh2$ndOZ2#g4dcqU{{UP;1UQbT0Kf$>8@4;Y zgvv_+)3h)&RFo)JYXqW7oHJNFHUl~N_~?=OxivRrFn(!U{$4PyKmuI($Yo48Ia~EG zp;n-Z=&%B}F}XpKQ=98*ZESt{(s%v7P+T!a;BOLKhru?X0%C{~8HPJH&4lTn-22H~ z4CLZ8a=2LdEdee7vLeIl(Y?$SeU4jTE*X1C^A}%y@?UB(K7MIhyv`MVOMnZ2ECiv7 z(Ew*cMZq2!b%fYMBLj)J>YcgVLpyK$)&@8)bYS_CDwHh0CJQ}lrQle#?Fz#t3r|&0 z0czy403N*DgFG)>`QfT72yKlGIN19;WLfvG-qzif{o=LPWTSW9Q3$3IqPz3Z@{L~7 zVN02aj$Rvde63P+x-91H*)Phup-YDpSaw^JTLslriEWVTn&Jbx*8|c-KAEJ zjXBway-HjVZP#_K?8@oi;14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>>Lqbs`tRPE5Tu8@AVw$+HlcI1~qF7*x zOi-~{@ICFFj)G?8eh%s4VTls{y%JfK84?T(c6B8}S|S1c{oD);)|0yUFZ^fl6?RmW za@UiK6%>#w%9hScmksh4sH+gHDiQW^(JRQ3%FPh3Di+B|l8BUaOSd#FOq66`P*DXsqy+v))Vnv$jL=;4VRYg;QD(fY)L&TC*MRV+wqZ)OhDkM{~ z#KXMBtV(l)n(Bm=MUu27(i?3PCc$>d7OWH0HMMUnol0ufRoL5d=waw2YC zF7m-5Za_yiO6N3674*9XHAv>?OGX)J>Xa9XWC**IizQ`ig}JE47fEK;N~Mbnn8^!! zDT;Z>M}Wh)w1E}4`q9@$dIAKV^r-j#Uhi$fi4dQ8Y?Z}J#jL7TMJ)PwQzonoT{{&vRFV~hIB@v z+=gQ3b%oB;lN|QdSYPS1ZwYm*57AhbV^STcajw;FZK3I|N~_Bq4p+LI8ttOioD zwAo!{ySC8&|NsBH?bg2sro|&AL4KfgO(bAcE>4{sZfwO~@a5Cb|Nnk24G?26m1mVa`}^*OIDY-q z*)?lk1uA>{E3-JPe)E5)2#*b$&F(K(i<$WKTc3RT`R~^=w;l;G&$PbD8R54UwBJ{7 z&}QRhWoEA^W7Xd)qM#@0>&m7)nS+H*Mp7%nKsSIVX${a5j7i?^F4re)in0fC*h@Tp zUD+S8N%5QWYz_Pw0F>tNba4!kxSX88z~rWzE31|kYbz$;e*eIPsb^2zICAC8ohDh8 zgv`|3!-?7H?;pH4a*|c(L0MU0Y4P_DUp{^N`1LdYgT#afygXcdoV?uq9X(xrollb! z9*B2z`+N9!`FZ+!pBG3;IC19Gxs$dgvRERCQ_UQ+5BjcE#HkZCbT! z*)+!;>-H_&`0~zAZgG9n?HyaTF}@Ydeg9%l&C^#~*S(W7EM#NrytnTkr?9&3JfqTE zUnGrHB_-0%&ND8*_lK2RTsLl0$;~27wl-1i@U_$8HkaM~#Vc)|dryhEX!V*q*K%){ zpLl;~YxVg!)(H)ZF75k!N^2E6->Q|y3XHwZ?WT?004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x00(qQO+^Rd1{x1H47E}DPyhf0?ny*JR5;6hm1}HUXC20$ z_dVzM_;P%SZ>f_w7pHNXxLK8?VJ%y$W@SLTQr6Khf)EUqY7-!#2{F*L4vO6j%J;~4|m zr4m~h5MW7OO`rP6F$zEdfbOfpq$lVv6_%Ih8Jxl zvQZ$8N1U`CU4pY$<*as=%ex3Mw+CugvWGU7LgtF+JGu^w#>-)VT}vYkhMFI1OA|5>}pj%k}H| z>&m|jlAB!4oX&`jR#db9TcYsrLmO<}ci4@tJM4UF)rm(e1htDp-BCn<(9M~&AoIKOo zAx1muJsesr9m_)w$L(h9-xDc1EV7PJZ4O>X1qIDOrOFVgw_ntm8Hnr@n zq0UFGRNhfExMYgVp}jMX)qE9=UJDvrGMrWs#R|tC{^o}guf4j;R|b64ec@NySzJp* z@xbSUt)J*E^a%iPNu9wJBVin{_f3tKqk|H}2^%q)M1y!++l$urpaql=ILsmzua_~E zTq0%(KTvOfCu7ha@7;}r;1cgN?K(^;aj%vN-)O#kcl6l!7H|}!9D0gD%WS-B z9*r%ld6B}RC+YK3pA^SK}3004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x00(qQO+^Rd1{x1H47E}DPyhf1oJmAMR7l5_Ra<994>R6E!BcsVM3}jpqseS^$4xPuoN+HbLSURyP0SyLCl$IK6 zmNWLpr>?j*U7NIMS*Qg7@Co~RtaFCe2aHf_a)~AIxcZnqU2aD(4$YJaU^@d>XR<{2|wX}=B z%Fn!5Ce;0&5_@;iN*)i^~W*pfy@PkQF^ja@62rF-)61aRWaBp3i_ znhr@ZF>m!ne555L5YHhBg)}hRTv%B1M4IQuBHXt}pw4}!rNygB?01ifJNDE|)d%fV z>ak$esAkb8lqD)Qb>+HNvTVGl!@N3~hVU;b(fBy3{SR`TCthYm*(Z|V!3gJ79R!{w zOZc2X@zF>yV0i{Q|KP+3#0+j!tU#W*__!#Q;rCe(QX<-SezY5zm_ zWJzVYiV~-W=E?+Wg9K$B2|fp-x*>)yO$9qB?0Xq;Jm92_B?3{VtEBH`m}>%AH4gS* zkL~ejZ*`~E*LGJUuMzUblsca5z3GrzoTVPUyQ@A=64?T3f*Kr>iTFwp^T|A#$`#~` zgr6QW&gL!cWdh?eKpO#JPo9nxOe;U_k?SnsW{SSBl8^&lYJ04d`F~v_R+u~Gj?svr zrV)d$#;sQRo-Um@2U^#*GP-P*8h39oj)9+g2Oh$7p=X9H7 z4SJ-k#mk)Zq}qSBjjc5o=u&bn(L2(Afk+!#iaiVfBKbwY0LtXh!f0XQ z9hpeI49xNnc@2{ajxC!kS{-zN00_85L{bIJB#JmOS^_=gAYoB%EfxHuo9s;!XI4%l z7WKgAwPM+vcxlxQ^@#s2nC1eN#Lev)nI5@!XKH72xPX-+1>pov$wFF_aOACZpeu#G zJ(A)A=+cmO`C*BQ>0^mgci5(lKzX1IXK73v6gF<@=dMFn)$;Zem#UFgZ5W=j;k`K# zr5-!_C!EOSWW*p2j~B0fp~!XHI$LFTtJHuGe-|JC_v6c-A9S4W3%m7rc^#vUjWRZN zQ)2%Vh0ViZ#U>YQ7Y8RrV{Zq)H{hl;r5clcS6m`Et)bwkvVHMN+BkhwBDVG)wmg6Q zx7jx_o0-2w;FRWReM52I^i)BdnH1avEC7ycCbV9Ir>~n_`(QRV6j6t}pXy7P_XOK+ z{IN*Y=N6X(J$7my<}fqojR?Y4@^5y_UfO+On@zHm;%x=lg2OTl@p#wvxVC*qOh5cg z{I1gGHsWDUr zc7Z~y6%cyO;LH0t%*(S&Z?Ad}gw={RiG%A*scP1QsjIWEBuuIy1`HO)005>T!2)#> zT6o`}i5ZLQAANBCA2^k#(YfIbFj4>X%Cf`fb+bPWMMjaB$^GvNJ_;NhU;FwsOikMv zrF_=oF>&&nxjXj%6Q3FB{w5{t4*&oFC3HntbYx+4WjbSWWnpw>05UK!I4v+YEig1x zFf}?cGCD9eEig1XFfhN0L!AHs03~!qSaf7zbY(hiZ)9m^c>ppnF*q$SHZ3wXR53L= eH8nahGA%GPIxsN3Mq}Lo0000004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8xfB;EEK~#9!?7erKoz;CO{5|Cv&@)@n$#4`x16H>)rM4=FKK{x*c3&<6g0i0nrhtAk^zQ3%Gy_cmqM4>j7NA z1-uk&*>bxy)o7a`!aWAJ+H51$nr-QdEm_j7#>U2+b3MM-3i!Dmzy(~uO8}Gdp%sw? z`!DH?eyF8|?`myTJDZZ~Yqlxg{ecgBAbzd~_*wxw*8{kK3pf+pemn8U9=LJI{=<9k zeA8vcm2bYnjjmg#m~AWk_=jQlm-ohw96FNv+UV5Z{vXD!uAS@gp6|F|0$jjr3Ntfz zH(Rp!;bluEZ(X&*506g>dgM_Pt5 z7x0=werh^fbBi}#drb}N)_AB^I6d-+!G;GVU%FcRS6y9W?LC$5TrRf;=rrmdyC49b z2l8AG-~uk-Oi*-c!l_cUvs1GbOFg7B8XGrCEMM*u00I$WQAL1f1M0%Ye-T^|0IwZz z091dyVG%deCChdW9X^ojTe;4~WmkLHyu}Otk%5&90{H^hK&T9OZ|Jo;9bE7MoS!)9 zf_!-~11!$+&@CZd zRj+JsuUs6lowZ|gwf2iPuHS#`*s=1t9_*`$%Wqj0D^HcLnVs@)ot?^b6mn9`%|c8~ z3Ov2r#E*YsSGRAEZW|wuee>#zy6)R~@Ou~X0bT?bY^3uK9Dr_0ZMuBf(z#D8>M6fJ z9Il|VLnEE`F*a`Cr@u_iW>Rgxo62td#a(xOp>(bX{AwVz7>S5#zQ(WFA9sq8>%&Gb zRsAt)?HH+Dw2{rs&B*CvM~&mNbKxJ`vB=L(oOog!^TPB3o(~s%0OuDN0R2b5@wv#| z+y3EwJstV?UUzi?+n=;O*I{(!)gDrrnlUtp#POlzd-mDHHkyR1XE8h?o~}AezE#Lq4sX7^d-uMdd~$@btNr@t z^|_wJ`Hl-=!1D+5r`7-d>c8H&X4Tw9Z@IB7mM+y87#4DLj2m+k!bsS_)o=FwYPFa- zczE1C*MokAAQ5a{`sq&}i{JO)kN%)E6aG^}Em@y5)@fU&nXBed)05S*KlxChSU5yjw!$YLV58&U z92oUsmKHwqy1~3QbNSU5^?l@{H-Es(XWti=eM=+8Vs6QV)vZ0E(n102PgSsC}jenNR*InBYOM09L6~`lfcfMl0C8AR?-Y@jmJY{ zg#v)r$7#pvFGWOh!-l1+j_w<|)hma7BP^HngpGcfB1VAbN|&kP43=t|#&zRn^6B0ESLNE}b^N$v(( zKK+YdRL0NsfX^Z%0KfmnemOG}zWT_K9e+Y@%f(S+WjJE>)Fqq;1_@tRkarGx*-YYI z+x7;4JP?GlFKqsofC~cP{K32cXbsT=Beh8Tp1nRF8B-T0qZ+OkIXah*{&ZwC`Wy zUizlr{@(Y#H;LDe33N_y!3S`DA$X9tKvv4ri;@+)eFIwssu-wM{2eV<`+Hson}2?; zM8vWk<`P{={U+6#f6wxJFN(@luw@e%XVCD`aE)kk$x)+l)ZkEmfB%sS~%)&fAGOazH{OP8e|`@7lC+AaKQ&~ z{$O5}bq4b9T4k@ge2v|22nekuiP>sC|1tJ4?_3Y^EI<>Hv2x|2w@y!$|J<##tw>pG zLzc_}00?SfIfwuTaG1JK+b>9t-oJX~y1$v;`tZ4)!|MhYG=TF1jm^)OUB00`$zqqb zvvfyVCYVbV;*x8n)$5}A@1|QXZf$N&etKe9|All{Zpc^{g)Nx@13%RxMFcQO0BE-I zG&k+aSR^ifdEJ|@+l33htFwj+8o>F1h5)dS9ooNTrP;f>(`pY{%*2SF1LKr4Ji}4* zr{ilAeJfg4J#qiQdwsX%eKzav4~bq_Mx2Ng2nq}gG_TMz0u*_wfUwJ5%nr`MG3S@y6Cd$?|23-tw6(Q`!(n4ZC5PX2 zE9P&;#4NTXL)x|arx5zzgV+o!~SzUm)9dMXaMIPLD}jN^oTgUWofvp zztwD&VQ%ONw;=Lv$rm;s@i?!X>w%sruDBwRy8n~>(|%R_I`g}_TjOiMnJECx8RLuy zL81=}ga8HlKXD#bg~~x$RR`x<+M++Iy6)XS`N>am=XyS`M_kYV&OHbO7K(+IWmIf) zyJ)o{JPeDZcF99tmlP9XC=`vpW;B3red|`SWM%vM1N)56qSE!7VZLff(q3T+5u(7` zM+{)~EWgI)*B~(B+|o5?oVyqVS@|8QrqJhi?bf>%TX=`+`f`=5K2^d3D^{=vy)d4lR7Y!Z;K4Q$GOByZnh5Gc}Py)jc5`HdqaXDqsGyzkT=D zK6cALp6hwNu5s2i0I!z2#S*zc?r53pU$H{TmKMdvCyXn%KT*2n$YAz6`xjsKpK)-Y78fEUS|QW*nsZbc=VHQ!F-2A zZ+9xP-s7Y>$YaDfID2mXSt1S24S*PG-jpc%yAey_Zxe~ocRzN^Kc4SG?=_FJ;R9$G za

g)z>s-r*2)hdUn;ui&gmOF~f+2nf%ZPD)y&7m1|8Trf+5kZx#9Yf=fp~zLW##L*pQg7Z;!L0jo72B>uQdSluSe6~z43R|@@=1%s`nkX=x?{> zA|^#d6Ep{iv0&>z>q0~X#u#yCDNoJtsygN=jOYkZVsgpkUMg>C}O-+9K$~Ku! zCV32^Ug>9%K~uVlJXMMcbQE!TI6rFN8fF{Yym@o;;PBwv;fH=(=+4byu>`h}Rs@gv zsvQfG{a63<=RWttb3M;D6wcNOOaRc5weH=uiw^(r#}eRB zMgqQ(fCmfy$cRwi|ACD+UJi|L0e_KNJzG+oDE4IFn%T zf_uka*sVjP!I+^nX{x!yva0tgBUbxTYghcMpZnYoi|2TrZ#bMS4FCXGS0BG`W+K`D zz=OOs8ZEcCb-0j*!t9L1liO@OxkEy^{XN|Be&eBg4lc1{xOc z-~7bDz#vfbrbWd+>MAj^qqQyZk4-7|G-G$Xo(2ASi?i;9pPW2C+1vNl9Xp@G?wM)h z$k1qd$G~v&_vWhR&)b@joXeFvY;@W&V;N`KY%SOFn>^)jHmy+0(9n1_pC6dH<(8Ft z-@Yl}^%^D&V|g>n-qLGyZC+z8_BG?oCnY2Y5tBsZ@q^w8cFY~!=T!1vLv5b@=G6vo zZjLl_mHKe4ko-fN^{t7T%V3JICMZTsa}LHB#~c1fiVG3RanW}uN`*eU@B|= z&5;A6-#>98f37v0H!NO}Fx>F)&Z_SZ3~$(YnVUjM6MHf{*^O?UI{^?KeYIJvfJ%tN-OogxOG27m@ zI<&MSAre|KVnmvAMkD|>=T-S(=eRSbCLgMm+@AvH#s|>X7w_}D$e)+zvi~k-tja`; zF5-+6ouuyv+y2GnGy{hw9|d(+%o zY}{z=Po>QNIj!=-bq-%yF54^;UPQji2FAFAV)#Vi zM~tz2{SvSJ?7>!KQnkdJ+IVK=5~JOBxW^f32F9SlnMFbs)U>Q>ZyHjJ;v7+4H@92Y z=H_A_<+ZMBQ}&Xm$x~nqniv=;*zxQ%6*LAxN_(v851{5Boe@UiUs`%vzA`m_{9HRX z-|%=AF6X14 zZ0pGUr=G>FH+}P)-wfd-hvT_kxR;8kA6=PYspVNC6A2@(8GNSdCn+Z)Mh4||0Uq2b zGH49vKmas1hi=i;j(=}@i{2VFmu4)PCC0g~@AzkB^*uj=;y)rEu9`%_-%~Z?&YkJD z#JBc5ethE9p4SCD8?U-*y>;tT{*ooF#~rWcdb+aCb-cL2qf7`JjBzGd2w|fg22UHx zr;bXwcm-pk`=N*Kb^2EI7vKH%cUQJ;+xA+u8SN;d@9md8Tb9VKbb^O_X z&^9ym{@M{Stf%+Pnz?(tig)nU8r+tZE2DNies#4Ry2H@DSBJ$?(=sy@5Oq?$a{o+Z zF9Q*Sqo!HGJ6I-j@K+aKwEi!jcx?C4SAXd*;JI*4;_lnGAIqyq_1kvT|DR<#Tr7FV zndcY5m>{qqC&)6=NQX9|IeY^-`P7>xCyM_%J}~k>4j(>zF#^-&wWb9y02$%oidLTN z?l4=Z#L6Ntrx}O{f+=P)MnzRYQI)4EUS;&v8r-Kp{hrWp*|~0fvhpQMuiY3kR>Cym zq~I_>GX};^f5{0%1R}uKB^2F*x=efby#Jjay8Y)Lx&Qb{>u~|+80ReUX7oUDHt$!y zkw~k*s?z?6l6!>v$^~ae@P;}iv>{@wIeH~e$}3r6D)QF*x8C@~Wng z(FMjN5&VYM|B|jtM3}2=hc8Y%v3BL!&$V>5Jk4%n4X590+n4h?!8!G=yG6H}=`aU; z&xw$Bdo+o-DbiH8FByTr8HeB&I17`(QwB#kJ6jlA^s8U}Z28iqJ-LaAnSpb?h^K?5 zo}T9JWXo^#srD_sW@k7iLfR!)a4;6Mzyb-z;Q557{DWfBo4vp4*6xLaSCk3pgP(Xu z<}d%>fBX#hyFVP2t9wGSg>lA-v7jwS5W7Ep0YG)TA0W(CcY+xs`(sJ^(k-{V>wACs zmw)-1VKsWA;GBooa?`c^(p8y>N~M}`tChu!MM4ITf-%Ves*3>vXOfvRrX^1?-_dcU zymhr|CE3xL!PQq^H@R=$zVoeQ_7p^;*5V|K{nmELjwhJqoOzuLE|5_I{(tN08P&tNJ6T z_)pD7;`rjC-tN1;{`GH-quv$h+}(u>cqY!d004lA(c*Y-Z*-`S^f|WF&b}xMqL) zGJB1Pu$W&(O&Clt#uzjaBx6J%OnU`(gog7uUc9?nt3HWWCQi;*t?KK{&xv0z&xyZG z7#rguqf3E#0zjRm^9)Y?I169rbk0eF5HoEyYIG*2N7Fe1)0X=ceJ(&6|G}$ee>WT6Vi-Kc8PkN|z7%{J;WS3ws+OKb^jrmY@a}I ze=p?upQkuq`T`IDw*A<#;`;ULe_AT-Ute{H-YTz=cQ^tt1 zr65A4S~z<1kT+-aFYk^W-hbj}jIr}V<+L2xXPIo>;!v9+M%*W#iIeHE01zZ;a#>NA z;Tviirp%q~aV%NWy!hZj`3I7^-W`(tEtW`W4Hsvs^3RWZUiIhDM7rP{5I&6^jHUUP z9^U%!L#LN4bOGlQ=Ys|S)CB+lwrkg}sc@Ws-7_X1uBZXW_45o6CzY8J7-Qg!gP@ou z&7`m?5nAipY)RCwMcTq$k?K!UA{k;aO_0Qh*faU@ zBm^l4DyRxMAH%I+X@ z)bUw6TK(?(-}}jLHW+`->Ed6&i{iX+0@l%ZV2o11ABrSv0>D!3$yQ5d>q4OMwt5Ll z-6YUZjB~*)qtjzr%1SNQlPgYc)Jz`Qa@DG_efv(FGfusX(XzRtmVMhI-MYNR$ZFyq zKe>zs0JK&J@sRf5U`Kf$=49cXIcMfEILN(>ub$WE+xzTJT}gewDMtQ0Wp4^uGNTC| z>MeO+lDEIU{sa=*(G@jUdxWL3^u2Uj;!EHE?stxytM$HsGsF3!0h|m40H6P>ul+2Y zjee~{duxuGA%X%u?}N&qwFeGQhOI>^XBkD@M5!@|oAYX(fs7o)|^Cx2U)lK(MjZI%X)>R^faOH%tA z(Ao#*VeP5{&zE;HD^lBUg~Z>#>uv9S>KrWd1-wL@j{-mg5Fhx!2j-$leorJOe^_w$ z!q-J`@Mj4DHlM1(K%|&toQI4ymb5Nr-0xU6F;V^0zkd1izjOQl{&f0WOvZA}wKlBQ z79-;`_{=BvEY=*xIW%dw+T{?$$ny)Be926}jf?Bx3nkxXh%Ya3;{zc#+jf6m75y>V~kwVtV)V01`?Xp@Y2F&^SimfAMxsV@&ktI zdViSpF0y2+t_K?CEBanK2*kLm`s3VH135e9{;YGw;va0?y07#quI~k$1)Q$}Kmp*} zw~tl!A3An#D1skX-O*glpQ@La(md15$!PSP(@2$YY-N7z2DJgo~FJI%5DR zvkWoEX}+5It)B{u#mhsYlNgso@So*>I1@DJycrldZcaIL!h=2iWbe|BfB4n+fAt#Z zTzCP`#Q7=!fVv0y_S@loK&;GE6BF_lfeJXBlP{Qx%I(~fg zv-#reJAeQ8KlEyt13Wh|eQ~>)ZEClgQ6v4lyN&};%ts9lz*U(s=Hkpf=#7RQOcc_W zI_20M1}*J2S*zwuXrh;w=mP*m3V0_#D3(9*&}nM{gB)wLOna^8EE(f2*ijf#^FiR$WkJ7krsYW^YNoY zfA;fV-T%S+?)zTy6&iPAqcfA6*Ca%wH7a7H$YGL*PCk8Ekm3ZuAeX=@x~7S-k~Wxw zGuHqJ05UC+EzHY&La5%AVcEqwH$lwjjdK2%dirb9;M^n-N2NL-U`{e&Reljm;b*VV zI$pr5fb&@Z%!4te+dH%01Fh+B34oh2g@nCIOWoByIa>Y5 zhd=zW-~RshzyC_)2@n9*mP)m@iF9v7L=6sTMT{xpr-t0>B{za;2GYzUrM1!(&h<+& z0s8tBC^jA%tXMiP-pRZIVJc61kF4gR&_rR%%8q%a0x%`^%j>pS-#t(0npUc6df61Z}Tg$4}?WeSJ-UTn#w`K;Y-f) zTcGqN5E!?#>*qw#9dNC%v#YteW$T~+`IlZz#~-i1#4~T$bFb_cmL5I_8_voX&h28@f^C^jz8mJiqJ74A)gPZFjVr#iR zk_;J=2{@#geBQM0`Xk-afFVQNFcL`14rI8&7y}p&$YlVZT8WN;G->Tp($_le?Y@(~K5i`nXM%!I z-OEk%!TeYVM2Zx7G{ZTHIxXXg z%#Y$3i?w70lNo9Aw82D@L!=~llyea?Ax!3T7?3cSfaDT_35bRdsBQu_@-MX3(4?WD z;gb&^3ZCh~2SITKhdhTdlpON&q}7~aeqKAs)keLU@)s);IWs#mCyQmzcc$TD62KII zNg$}(ShM1iD?j(y|9W#zXJyT%jec`7=?GFZH!?aquy6m;rz2+e!M;@c-futl?el^j z?KLL=>Q!drix)4tYi?q+wMvnG!&vDPl{tert^9Vz7zm013`u(ll&+!T9=L39aQM$| zy6J||4}bV0Pu_OhZD*Q_8>p-|BHq5Uxv#mF7J@i9DXkej@3dKs2H}I61G2)pZJ*moE(^qb^*Dg77Ol>2Cl)^WG9mgRH8qW{RqeoGK!(O2|#s?t?=>=zX^6mSIg^2(h0Q-t?-l$)f*f~Nczk9$67hGw z=N<3c_qoq~{-s=)0T4G`b5qBm@S%(6eE)Loxa$&rWJ9DPlPx04+KeW&8O=z^7&tSC zLuo(AUjS!{G=eUK3Iqio4Zm;Wb}ulj1h4v;|BTrYbUlY8a2&IGh9f}}po!p;2cKLx z(Y_63h+f;3qOM^F%W!2tzK|$$eF?eOCEpn@&CJS-MT-0>Zvo&aP#(+lX$+sAbNpv$(MlOwAAE4^EoJ8 zJeX+@Y4s&g|C6cnjM#usrBmsg6 z@W97L3L1Jof=TdCA}web&w+u0`Pz$9aW2`N4D4Uf5o%YD@#Z<5;yx>056t@Tp0@_9s8L-lVmDfOGDg$$Fk`yk-Re0JJqn zetx8oU!~aSdaYM5&Vw`IbhUtni;O_v+(byWBW`RoO0!R2=6R#PzjEzTwr}^LhfZ@i zfh70Q4oOSWG6BvQe1M4;*_T8F4i3%?&NvHsJ{fqvut5`|hYl6qYf$H9rqL1+!d9AU z9C-dP=kfJd81YwzIhrmwKZ#&O+Eee!GrT}eG!|@G-YeZuoqd(fMzF`{=C5Vlg|j8 zBomxL#)TnlJck-{`|aTW@DHskysG)TA+bCzd5j1?8Xo_%freVmIU@~Xu0KP*nkh83 z$M;@z*~R1k_QfCKIo2Q?id^EBGbCZuE>0DKQF z9MVjY%N$~i(?X^qpFhFbGsacVNnrE53@FnC0RRj5(%cV?#|fiX^*=q5~;RJ1U6^lf3gT3fz+`JW#+a9|cMy!i~`Pm|NqEpsOk;fcW@T+=qz_!!7zws|WnEbad&eJl?>1Mkmwu36(Ivsq<;flrKc z`pMl9Z)7aGCla?Gx#RzQWBM%JxR;FAya3qo$lhaZZOOZhNc^KUe>%&^WKu}dq+c@Q zjpQ~`p>>pZWO{UT*L#*PUpju-WtaWkqmMp1`2rtP0A$1oMZ?lQqwgbVFi5hQLByFs zJ`Z6*01)ctz{p7DEl`P1CPM3ckjFLjS@HNk8w?;uN|)iQycUKSJ$88C;7N&685y&e zW~|ipVNc!^SK&2_S(jW9S}M{!?g@}~m@DQ`W&*y{5Orf-KrnXN>8A|=z!`(ZED#7) zRbjJ!9yu!FggfdTuMOshX?nz!&TcbgKagq5JbdZ8r2~(B`!TI29X&TWs^$)i5>D+W z`CJJ+FE*@=*~JS&pGdyeR~SeX9_f!MN49vD^qR1Ca5!O7!gI}f`}MDivl3)zAuAj9+ zKmA@w&R*kVCawG|7eY2dJ*VvtsHf4fx>iTF%<4E+^0`{Eb8@Wk;RhdlxbV$ye)GHU zeeZj#I8_J)KWlV`WjK?NF`RBb0sttjAh?MLH;DNRh7iq82oY2Bu_Q+@Ea#R@ao3f>(9onDFlf^^Yl(bQztNV*Q+>^7s2_& z3jC5WHnv^IVud_0d!=&ZV!#fYW=av!Ja|VOQ2_#Tk z*XUpW_1~Vj>#n;Rr_9L&|C{=aMO*reuAZ<6o%VMs(lEI}E)hFeInGKU=eQqZdv(zp z2f#LL?p>Q3kN#muE?yco+ewr6vTFNZc>Y0-L{RxR0>?k@w^+?aGtyfUh~L;^HZAHD ztyYGoJq@j9QN|1kqQ)G~IOmoyn874S>-la+C$G|T34?}%PXlCv5eK10Rd&Liz~1U1 zcaL{uX1{mr@#Fr;-LrP?yH~ycrn`=8+qVrBjLkkh;?%Eh;8ffFVzB zp;QWqa*_V4#nx=LMMntrOuw_g`5RI5;5pUIMa3O~c1F#W;l&+`V;xP=ur20fkq+Yo zc6$f;KL3~;mx;6RpX=fA?G8{q3h7eQNKKZTl)%*jVS&hJW^=E)+C9^XKyduL~2P zfu<(4Yj)b*p`Gc?6=x(Cwp%n~eqF79i9C2vFc_CnYlW|?u2CrLx$Ke0@B35V_x}vQ zDC&F#05n4AWQNSx%)*)7V?vNI2sFtQPSE(0*U@$|M-J*J;w%^?EAHx8R?JXLWAI9U!pOuHo zd&g7br91Du)5n5pe}R4YEZ}t|01h0$TsB+S3SnL3`Qz6UYbH(xG&yHn6<;re0TD4p z9!z2Ln7LRJd8xUXeK+mjzw_{0-+IlRKl#bMBlDjjmf?g5XRP5)JS`1?5r<1)oH1%L znv~%kYLSu~sTx{O%uKy6EY`G0p5S0Feyx{+z*horE?`=OvVQ;-X9$T%4qH|vv8E%0 zj+B9PR3Z@)EMiF*^_C(^6DqDk$XsH6A=f_EH5B%hBfN+Jz*JX9m6uXl|u8})Z_;b%0uJ7 z`J2D_-8=8RGY0^MHsZ_|p_55VPiMmh-=i33jM`)~8CBC{CM~0K7OEP4dt9~{oLTj7 z;WIxT$4lQEr1@q-z?s_pWa~h65fVS`?KK!OG+`K-Cs3}nMHH791uJwS6 zIS3avMjYe}E&KuoUjv>ZC{4IwWeS(|#_-UgJic(>5Pq7U!o|iqTCCe?&+H*_zq1V` zv-ZnqGWj=uzxi+PyX|kzI?K=nya3KSjn;j>KROn(D%mO$;LxZ0M8pmKB9E=lSPN1gtVN-7v@4F<8tCl8V zO4K_r2c@#PvX6b^RqPwBU|_n2iGqu&Lr_GJk|Ayhw8l;JHrZI+5k_CLjd)0asBYe9 zLdj7Wn6BZ=k51v~V~h$#fpV=>E8DeyD|6?ci#)Ou!^7tVNyZxquR9X}0LI3kH(z{3 z@x;)+ZmmMgOp%NlJW3Qa=Xl8iAoyHRW5BtDU|}MytWtHVZ8kS$#%iHUI(TcgMW#7e z;8I>|+&w%{ztY~lb{fSiTT_v4b@ z8gAQ^z_lyVh+092vFd6ZnW*9Jy*Ye$`wSjBT)^NJR*W%0tOS?u}tXcN9xoLuig000X9q9*$4fFfi?4qUgg{1VeI|GH|FaZVsb4 zY7#WV#GLPY9uDq5PQ%mV80GP*j?)u!s_rH5@x9_TD4DpyD zqVpV4ticj`#$fXo(4?3lqOe4UwGqtn7^F-?vV}aOmy`UnpmA_8Sp~@w6-& zc3m2`tVv--YZy}{55L?uhaCeYR2+?_n2A(aqT(oYrfn>4GAUp7&4HQPHJXgtk|nDK zhlZ*(AZ`F9iBq+K#?5ME(=~p-5D|Epcs)x~4nT*JxFw=`KNU7sUv2YV3S#v1G6Vpy zaGKV$-87-5CNY@*Io8@4Y)NcJSi~?wIplc`o~%I_1X2vbF%i=-WRO5cMv>$ZkkT-i z36~t~Dm{g5zK4p@4ohU~mHt72(#z2R0`5G33j`GRxM5Wa@7dIZrL8u!4j2cdU@$m`oZo^BL>fvHd=0q1hF^a#W5D3FgReb4 zg{=qkh}iI8Y1aeZNBvUb(-CuhI%K37 z7$YM8WtY;<$G>$D>??SCL3#)&i_now0-}OsoREw%SO$mZ6LKYuVwu5l3`jqMCchP( zER98?6|V2#JGpysoMj=*ZiGY}nu0Qtmn*Qe20#olJcF9vgUyTc_?;;0danViPbB^)c7OtdB} z#4G{H7!(nTp2lq1!{D5YV-saePn3|WCQwi%*xE#%31}9EWI^a}fuifB3M*=~^@fmy zsy>eXmNITwmBNblFeVEwe){w*eztoKHJ@JRzVX;3ezs>0u1|RT zhBSJcY^?8&;jL?u$XCnQGvXt{+n{|TY>^5pxKOGB!7A`r3E&QxsQLso2uBai4(fqF zxaF6}(}}iW&GHkW5XLgyEyGVgc5JfF9(@5Xg4eSE0P3~$ip?I0#oD&I#hHz!&f1bE z80V}J6?n(aP-c@pb;BIrt4AjWWH zqKZe36tHWsjEbkxmNXFyOZXaSib`x;6veUW8tyxg53bu5LTko^$rxrz4h~LCK%fJR zLLkz0CLs-Cnh_KuxCAH?+$7V;sF2yCLZVMwtUIIK#Oi9v!ZNJhHmS8KU$K}{rG-@#H zVQ_vNpS-pS*RDvykQ}}SVwS+ci5l+Nm&3jL=CFUH0$&kY;s%mY165C>>S=UmY%FUH zAst~DFBUOTEI41>UpS>(Mv_~@1_u3MSHiP;+d@qr1Pn0D}6 zSGM47Yf~^K$86chKR-Buf7>>VVol-3)hT@Vie|iJbsDQX!f1{g2%91Z?Qw>P$?swSN+(nE<0OQ=Y*X4>&++J^&lgjIbbt!U3Og_?$7$3=xKHWLd;mBqCyQ47z1; ztwLAM77Oo)lKiz;GTzzO)#a|~QKe&Jwey0J=Un5BAOHXWGh-!hio^2)fx{RDc}S-*)WCJ1 z!N`D*IWXfW`kKr5*p^mUlH+?jrg8V4IsE$OX56wajcmfivGE$d{MaP!*`G&e+QPdo z%HYP;DfG955Va&gfUg4Ar@8tBeg=+0OWoE)7~KxJG*;+qN;;HMu5RC)=FtrY28y@^}8<#ko3n?_PVoYdybbt-TLQ4-25enNIh2 zw_+Z)k68_msbpbKdAhk-faJi4Id;IHmVlIO=0-k_bI#*~rcrSXZSo~t9z=t$O?rMj z&Eq`Sq6FGwG7rPp>)q*W;VLWBI-S#eX|3ctttZNP_>wq!Nkc+%X=ztul=tG57*^*r zeFh|w0RZMphd8MU-wQu&Na%k%-MQ0OHbAlUSA3O)XLe6#S1ytnYN$H|9kr62*)>t{ z?RgW1HM90Pf6{|?i_(%G$Z>%cYEYg!6DG$haPUk=Hdyr8{@1!1bNUBZZHb zcXmTnLM^2;7?o{n8RQ8&CZ6jC?bq{f1+gWe**lJ2_jaP>`awN-dssm$U=#?c{r7@d z$K;;LWj9dEuF&Yf4mGXPm*BGLPVb*hQ>QK<%jwR)EW3!b8x`$8z~N&h?-Mw?p$8~i z_@BRgoz}wc1MTsZD~f<8;8~fS5U7l9UDnc;I_zG#e4BYbj@G)sZ9e4O+PHQAJqrA+ zagO-Xes)QcB;vA*gY&gvWPfwShq1?H zXqwoeSP-yMIk%ccld_wl;(SZa?AmVUi-|3nFp*8HML9%I@t(rCpdqc0^B{&13g$Hr zjak`Es-pkiDV0L0SEPPbu7h5G(BI6ITc4@NEXS>n_H@^>b8|y<0*K$pU;ys#18zbL zWIsO0KD%TY0&Ir=rp6;MOT~XR0stUU6Ua#lhb`WDc9!v?C;$`ukMWu}BXDCb+mqBg z0WP=(Hb`39ROW0gG)neoi6y*5g9Gj;yBq9b4GazRMA-AoLZN$N+M_allVTH9rl&XP zl*RD&7-5HqY~`x$5rtO%Km>v|ewis1Gc`}lem7|(RzvKu-5tTmFf1+oZpxTV9^O*@ z``dgHPSC^^|FA>M=UpP{KXc{|k>Uf`3MY-N@WpUARNR|qzp?-S;(Gb*$(Z+xC4JtE z*N6ifd83+2=kpsEQaIFV8N3;9+C6@<)c%F1Fj4~n>j{?qC7f1eIG7tsSmO6}@!BRD zOIX5{h6n5?##HO$Cm_Shz6CD}X&+`&onh)b2@i6+L64gl>+8y-IZccZGNx3nfCzt` z8#xgzFe%kF57x60Xw&?PziVa%2@Dd+1K0ouNJgO0Ovf|^sD(h#0xEFu0j}&e0}pa0 za~Kj++6mxLMWEkK8Tqr$BrBA{NXz@k8sdqRelKZvG30|*P&MrV5*Tgc+%k;9?1*T> ze0q>lDy^v>aqK{`4hv^9z{b~v0d>g$Rc|!3A7i5#Ko;XnTyF=7ZC#Djdjn}*jd#I` znn@bKD2NGrv@yl*)S|4dd4uF2z}YA{)WpIMzFy@f zhMZ55lDe^sCLAmtT+%6I(R=G`Vu%Ycro_tqTZX9_9T7B+ArZOJGLS=BQ0l@!frrM_i{vvve(@YP`WL@O3x@rG zOs--Un|-pjug29!`y@mh>rFx-;J5-8Pl({7*YDIZ;Epz}qJz`^d=A?_!yqt*F;Qt19WBO3w&)N}qKL+^ zh{eX(_%~2PQe3L6pFeyyJwl1uIoeive3aS~8Qa+!GWz$-jWCt-Qd8zoq$VD`Mt0A3pV)}eoT*C4X3Fy0pG2!W7XdOtTBWMkXR6)%J)=r$YEryCZ)Va zB{o=0j4d(sFW+sRE?G|tLgv$0 zasnZIE^+x0INwj>o=xbi&tpZDaupEMo6O0<)Cf?@MI84m&1(_H=}F41V~&;EuKP9w zk0|qeKcJPcWHW+9=YUT9s>RM#qxNWT{l!pp;xw1K*PfXVogdO<&&^ciFwc%bW71gO zS&I3qOy=GKO5a#!DwQCzQKaDSCZD={%^F~S|CSv#_+$agRb_`8jDwzxsdF_6uyMKS z;TJHx6+`>7=z~K_9_a5ZtUGP2VGR=|a*<<6I1OGcp(`X9`c3qZqmYO!fr}nc1Or6? zO_GQe5;gGA`pGhZM*4_(SYu0QEQ58NDQ#!K(bHJM9V&(IeK$;=K2BjDMWKWJAtYKK zOpp`ClL+7nRx#L(Y_FX)EyWI^Hu#!F4QRb|u6b8W*$?h7d_OOhDZ}7Pt%phi*y(Okk&I z6mWwuqdj6FzfsMDTMU_7wz!`^{v<1e4pw1ZSY1YYR6=$U8r@nx52h7vh#zmP96Q_= zrZn>K{)bJ(C_WsNRZcV(f9M_u1G57@%cQC9Z2AWBI#GJtmtR_w?}MrsocmvwW9dzS zoUb{YNITJx!GN2KowwOk_0f6I@~xhvjGlf2G~km927rzT(cEhCk9+0D&TgrJI*J0H zlwW-~1pzLTHPOVzj(+b|0}xaI+ZWFczFep*N;oYJcHVuEmH5w;banDt_d%M!x~Rfg z62ZZ+>J^c~r0wkOioW#2WW5-&LrdyMV#yweEbh@8T5N8 zLs%5Cz+s0*%(}NrS~wcT>NH3bXV!2bEowZVO`1RW`tA z{RbPX7z>09C8HloFcAGMpa(dwZNC5FOH@US2tZ4*ERC=)v%L?j!Cb7@K#DZ;GPCwo6h%lA}?#@H*F zR_`5-bz9#2b0+xwc=2SOTwfRcJ|g^jm&N)FI&62RB;p(ZXbKMszutp>n`xZM<$xY$ zW;#klQNe~LWe*5;C)vW6>RfVw@g({0g|xQ$HDZZnOmRl{04yeyby!)qX{o;IoAm`s zTM-ir*^c@UbfsAr_v%=`r_2Rx17sPQ?G%B2-(S;Vz^{*3%yNRG@W`+(mK+S28AmC6 z+Qp6yI{lB7aoOydj#pBhd{G3<_8&5bsrR^ZTFA@m|6ce%9(^Go2DZI+>sY(YC$wRo z66(C9nH`#;L*7njnu^l`?*d>Jq3aOpWyuA-`Izb>5ACR_Ttmdtgr5L}3$n8W)di6> z{5yRj371ebe~FnXNK!!gHQyl}MWBh_5FzfbPDWg6ucG%rnkZ4DQ}o@48`k(!n}cUc z8#g!<_K0twD*nGjHKrDR_=E=^7OyDE+N5-!9IrA zGNLJPF~Kc>k~|v=USiWgK?>ZhLYRrkA`rNTc}N~pdGh;cD_#a=vcBpC>)piC@eZ-| zc;oLDl*G~FS0!TrlHXa+w&)xapv``RQc+Lwue@)Q8sDd{shz_Xa;w?qK3v+L^{>)@ zS`{Af7|fgW6PSpGl31zlMwkm0I{f!zz5tW&Z>(d!?aUNVNC;3Bta9J6NbC?ziU|ga1w{6|SuVyJ9!C z7UTS%f9M6AnSc2smA64w%HV+|5m|3F4nT4c7dRmqk{qW4nH?Q2gOejcKAzT%(pO!X zONu)cyO} zb>P!%yk~Rfc!F|nKPc!^4;Lx-ll$V*pOg(?ZI|>JEOlAz?+^@i$7Rn8yA&^mh?HnL zt_Agl7~^EaO#(K^kZ0=on-BBNZ#UTJ(NVR5)KzrHUg|h+oxNsJf?@rYs3YL3$D!K; z=ZHqQ>5OdsN$Fquj#y*F$Y_?Ep?pq0K0`?`1LFOnGRVbuC8{%^vomtXLuA)o+JGF1 z#fjS29srv}%5Y$&_ucvO4w^ZPLVG3o;OE9x0=vjA)RHmEWM%-k6g+ck6PsHnGYO+0 zfg%0{Eq$tJx&z5x6FDa)QpVQG&?I2O+G;jRQ{&^YaxL2AvAbq&YW?_AEz@%9t&h0Xzk;V8jkDd3CFpMV&ZR;2I>GXlb9dcg; zlr1FgzpJCV=K%W z%O`fmM*R}uh*|9j;r*gaY3~9*dvh=B22Vh&{Y51dL)80?of&HzCOJLPCuG`k{KTtg={Zu1wz)050Vf6MU~f69d2zW2vnd9&ieeV;@B zLb7p>HG|BXnMv-l@(=Tw^T8ienf$^`8D05I-}n?!s(fRg6?`n~-H`FW9B9fv=Byzm z3JG6?AAVP`{6g_%k;*$7gwz0sg&~L3fiEkhK2TB{qD6us2Xwyv5TcDE1(#T`GVkk# zHyLn{1L@+^e#WD~HPYO{+dqUQJhHNrp%i??MpUMV)Kr*K$o=bra43pY;Q-N69zs?z05mET(Xl~Za6tdug-RK4b9g4mo zogm5>m(xcA9`~zrmSP9l#YUfK^gD9C2_ zC?k%yGY>=3FLzMTv5Etd8!cfxV@n?dwqTL)**qBXp6R4Aq?lc}T0BN3|25Cc78_Uz zTFkdXTIq;~qJ&$brzBeH=n+NLL)`KsPm1Y@^Rky4;_!C1ZG?dktE_nixO$+0u8KJj zxg#`nD2cd@Ck6tOHi!deii4ekijc?Fz;$i3u6SWzq*-DyDFqv!LgHxes~hM*5^KGM zKC-=D5iH_DbJCz0`C4OgT97&E6#`E_@Dr7_Tuz5H=r#SfdRPlDq}{uXMI=q6=z zzyd>+zwi~}AuGTo3Tk688t%Os&sEk6k*tZEEy3w#AVC^apYFvRYQ-x>0qIeIb*Bv5 zA{)X}kQtPtm4;Akg*Tj^IVxBuK)a7!9aXahZ_#;cD2#t;KC4vys_CusoRs8w7U;=B zkcutNGT-!OsthS7&fh+sp0EWn%oWH!$8#oE>*!`XjT{UC_(FjJb0v4zK?i1>Cws}_ zqM($7TZBYK-fo@t@=@4G^Oo;T73vF5#929hO`#ENCWrkAI6lfeu302sv^wfnvKV$u zON3d`Gve(iP3H)3soC&lP)Ko%V-X#{=SnQ6c07rpQn{fz>K4j?wL>AEgd{iI;UyTW zv#)v`rt-)`&7`CPnghUF#@}f`1}8*V70#?w6Acw?zeuM4n&LDXG%#$H3#UQeSbrm? zh?BI7yuQo=W|HNHrXv^j^+AFE1q4HxalidCir*u_`|0vNN$p?g{0R(xIBipG@?MKX zR+>i!>YBWyiV7ev z9vmC^1#Y*)F@&S1rgR7Zl4VCBI>J^$6bx|>6Pe+Guq(?Ov7<0KinGnKbGm>-C8T92 z*zGfjhyjqD5d8gTl$GcS$|nFusqvu)Mv~e%j;AVpg*Tt5ukl;msMX!c{P;YGYt|(k zycdp6I>uT@M!Qba+Ns7=z7TB|!GVSF4_8C&FG9bY{ROm3;g3&)1+ILocIq-Z|=!m)N3rOK*0 z+au4;79C)6q=+fkdlTYhCdUdrJw*!?8qO?Pf6W4=r3Gr|^bOl{SvWN6rqW zz%=e5y`b?(9l9HN%|z$oQW2{&#aC-Ck#EJE1t+nW@@(zSM$B1gW1 zD(uWF)Oru50y;B9Bwy^T3vq63F@r6+CDO1xg32FX2qdwb6R)tk|zF@&hUEp8Gi3nfm< zJajxBu@YWD?RD%y*AFlgOe7~rq5tOpW*dZxM#{SPp2=mRYo{9dHc&jEeLKeMS;Asc z^w%2Ps(I@SK5&60^h9NTJ}%u6ur#RwgZ3PYrec!?E6d0{pU0hoEI%xXS=BIb*M`oA zPyB@(R&78?Z$29-j9l}KAv7IQ38oKq)H~oEs<>7YCoxBSrZD_aSyByVaXuNB7>bJ; zCc(Lwj$nwHoeFJ6VGy15^a#B2#bvhBc$(a_{5ox>lkCS4HMh16=$LE4yG^0C?&z-U zjs}0D!5lMEZUCD>judek7)fSgD9NWK25lJW}r8LBK!GI<-<|h$Y@IY z^SLln)caxOzAr=@<-gs`RW!0iHr0Tu0%B4j%>iY*rH&R+)FJGSd!UPuYez8HXLO-W+t?=< zTAmfsDy-H*rwn!&*%Q&5)E}93VXInZhaOg2An3PJhqUIKWIeDQ&3Vopd`QB$mn&`c z@USTcKA59+!%l(gG00q8X$&5p`I$^`I>jL-_+@f!jRST_WU;>P0ZKB&ynah5E=tI* z%D8Qb@ldA3$dwIZs_BU_g;qeaL~}y2i#>-FirM5Oq2{p)Nmq72Pqh@;V$RnVeAx$T z@bi5z3vt7d@jEwXEsYnFFUuH@%iDa%Dps|p$4pA3)tH#*E3n{X(spF@Kk?epHqDMl z8nCmjkunFc^*z)DwFN!gKrN&c?`t}`^8A>Zu|Pa_U9Hp7Q~aUu?UloXs0#V?4=u|< zUA<_*@ia1f6NN6e`Y?GXikR^Z4cqlDIl4apxm=E6Vla=YZTP2ZkPS~}!0s!mCyUr>Z#2=zYga(GK^adR_WLh#T5Ip4&g6F=6<3cJrPpAF zhGzBAH>bq97?vghskCS{{5D8Vory2!4EcCiSDK!A<;{mz|3)-yaqDly)v>vj1hpoD z7WvOF;eQ^=x^HCTxTsZ+D?pezI|ot|RgFvu^ff-kEIjDzI+Qyu8lze%FI5mUKJ`A`- zSg^RxsR`63%?-c65()GW1ancaEa&nG6iSB`an-u;pX)PKHo4Xz=-)~k>PsPHERYbO z{12~!wR2`0)M8$%VdK~vpnwb+cQPYP}29FP^$OzJyFSO8vb>k#P zrDxW11duKeMx8ev5cN5d8zl2uK}98%TvocH)_QHPVt#9jaE<|MucR+WbfUiSl@Q}| zM)wp#uzO$MCJO!Uba%(_?*ZNbMt~&*vdC%2_~CyG(lSK494^jXZM@(AO)sB+m-bS~ zP+FJK-ddhv*N{@4rPODObFmCt>&}G{pBBSf1TQOhL)?t>UsAqr^18u2Msun>>JiLj z(fhX&W@`+Py{S&lC~&0%H_@rw{DBuY#Z>*RW$lYAtMwbh$YxQfvQt&&FJ#|X9i9)g zgC3_8C{saU2THe>@88x^m5WzKF>8p}NvYDBW#-{in8i4t0NzhiLA#>y_i<|`W6UjfVYbiur{FDkVru)g%zJ*1U7o1?(T>rU^SyU z8s?5x{IZK;;0tUFLf!q%6ZUR~!|a6gA2ru+=7_1MWdiw5U5erl&jKmybyJ3eI;yY~Fi3^fhtWJ|_fpKH@$*b1wV^W~ zWL<7c_;6dJfTgs1^w=l*$aAY~2JY!)sD$NXH~|tm7)+ikPiXMUc^LQhhS1) z+4Ta`8Z3hiKu(Uo2{Uj5#gR>uGk=k(!;~)Oh%f0TOC)_{p31RyaNO+jAE~|$y0kO; z(BjCp*F3f<+Q;^`eER~*IraW1jKe(dB>tUX-#5DZjH9iO!HsM-GCaJVQMIu!r3e$0 z{aCt@wL*k2;i=KY$Jb2WA)lA+;ULDTECN$Njw){Q>nK0j$IEL5@wl+%U?=F1>tP@U ztFre1?S(V&l-H?~KfvC-jWf-Khj8)QB_Q3F+f0_j{_6FtLVy;$28}h6*1TJC`*Otf zdAmHUom<0qa)F;B&otN#^r7Q{+eG&BZnnAyr(&4Zzy#zeE;KKFw1hV{R~E+6IVMh?SszCtO2pvtueP=>qs_)r=YK!^XA8CQ zUeD@2g&PkC+LW4Tbh}Rrz9bg>Q-K68ZJIhCs&#XTrP*07PjmXiv+4UfGt#tV9Wvtp zX?D|!hRQYzqq|3){gc}U+am%;QylvZ6R|5^=m%Tfeb&E|$cml~il|OAYU^pWbKKgdAxejZbX34iMvG`wpD*n%Uc@lD39ib(e8I zUgZ0Y1v`32>WP}s7}OH#zY=BPJj@)@!Gg}g@2^bHPY6~FEXHIh&G+gq)Yp6XB2TiU z`brx7%Hsbs+<4iK8@oAS8wJ>7imvm=fiW4;x1Y}PPS|~`d;(fPU?b)u8lH=DOMD|g z+(-`G*xHSznMep(K*3^`OA+aJs9>gy@*6>?D_{nWjky_w9=bJ!-)(1+2NieDp3UGI zSh=_A<1XXer?2iLK-C~obmtDZJh^aueVq&Xa4VeyfhOoam}1geAtO)O^jbyCS#(>A zgIsI3>#3g2|8Pj*&T zdG0}GN&7f|f~s(;DL?nVaH<3T+*C#*y03%1HvLfNg9! zq~JBNN1hhi)0+vq9OsL2%jt9>&49r}**N?O{s!vYxiU%NDq3@wVU`$8O>#m`^k(RB zHE)nJm~>CWr61TJt<}nzYWcw%BTI6!J|=0g@o5an%}N(npQG}GIv}iuX5ZK*vau(1!Lu-^&!eTKpxq|BnTK{~i_iy7GAhS|R^91-$|F_zmS z^|}OO^DubtAuVTx*M6_qiv(_hZS16vTEx=@N1x3vHKM)4C zwI4K#5|&$7rvBC>(x7nh7Epf~{b+nQs$H=yeR$oj3=_z-J{sbRJ^5Ni*ZFe((I?wZ zwoxlon-t;uP2tD)!8g_B9>s}4vEC;HER5YJ64xH_=2}$k4)!M`roVv((Swp< zVLx2*EFi`Vk9G@eWQDPsKD=N6`)xPUKlG3D8Ay6<>Uv#0`WGlNH-rV4O{bScw3T>$ zC)iD)7m*e;XJI0;iqHoMsV^W+LX$eMT!(XqiE&hqQHk#+EtbIx_ilsd9>lGAihhvV zC2%W0I{hW90dF7Q{B(JpSkayv+x8SdvT5<8{c`WRA!z1m)=smDk2kMi2eB-?Jv^`n zwd!)T-3$8nfZ%`L#i|*Qu+S6r>Ac2nFK8%blxCnpVR^%?`oJw@v~~d-Y(5S);tp2N z!oTF$bB!S*pAv7qyQ6NZV5cA|+JDC$8tGL7j}TbL5mj~&E?JP_$O6-eUG&IJ*1G>i zn)eR3?cnyXwo#hI{1V{`5hTl&+ByO4USEWn4``E-j_!V*L(5p!JRr&-$U$h_Y1l!2 z{XKy4;(}iM&5b;3ur7D=_I2&aR9Tz3G70QKdmrDhVfJ#?rnce}FaYK!DevVzY2REF z+cgaTEf%*57gqhPMTnyEVUGL!Sx`86E#B~q*RpsIMTZow@q(-$F!bW#SMWQ)qHlm_ z%zW&7uE!%*TrR94lA`%QxF#|+bi{US4myn0uf3Ch7$!I$K(6~;5@PqSd(5c`d3Eu^ zk-p#d>)Lm0ML$48b`@5ZqRSG0E?#GLq-*K|`^K#oOfVK;3^1Ta_zv&6Q~*T;^k*F! zqIURUK(SzIREV)JHS#~O%yy{B+$!GLgI2$k9{3&cCEi%N)w+%^%~CiMM-9Vw5IZ?t z<-Knc1-Tt0_V-aeL7ItXgN}4VS${|jqF?rZ>5(pkpE`EnadI_CSAxZW2h0Fu*lHPR znV$9ya)XolJCS;4cqS7E=i`Zv9-|;<{TD+JFBwqAmd3UG<4+9Y@r0CCjKD0mZxw8) z|5xVlk6Vw8Z^(Lf1gv?1Z(-kN+?_^>u=d)oU`h%b08f-4i7#H0)?=tC`jY_6(jY%x z3eCZ)7EQ1sI$KOlE z+s6c!Gr0&=rwDKLq|hZiKq%*5LdHEkm7|-puSD0p^)LVqg32OB@5&o@2T?)a-7NM; z?b-Mjt@kv{Q$s9o*1W$;WqM99-4_%(cDdh6_MO*afyE)Y)i{TyA>|<!16D13bTt z$15RuTYgPy){-6(O5z|Ye?~`GeR$r5f3C}~!5T(>b8f3iUG58b-THW9B_Z2lcOU0o z9>^1dX+;n5C)0(8eV&GPK(@-8eG*olbwZhRITf-C`V(00qg z&c$`K<1$7H5mjdZan+iLoYM3O&5>vb-`mRzyN4++d`|1HFXdJDm^vm*ziVt`iWK#GRqyc#KoZd4 z2^Z@%O_`0J>vzEdzmR-tqf23=ww=%!O<&m{HH;g4qPd9}G<<7kw9m#jX=GQHA+{FI zmVI|pozMY)H{lX6dtzc-pE(PCoroj%Of8KF$t@^x7Tm!V!%)U^X^pH$+!3mXi1)ozF1p>^}pf~nJxs~M9ND(_-h<6^6e zjI zJy2c#i(rJGl}IF-m<>$D2?f@EhrK-F_4;z8mm%>#;(uD`+ujVyLhilQ3%JC)+uSi^ zqWc3x7sD1Ugs{-q?&w^HJj$KT{_V}X8^2($1t(!Y`*P}b43hHuzt0Y2Hp`wfcp{ng zfDUvlPd^S~+cd$R8hOLIUb(_zPJ?}CKYevVjmoIsEfnLWpDsS41v+W7@xLv0 zLC4r>6G?b1gZZf`Os#THGXy|qhpMith>Qh2VwqKT5k^`7lQ9df!|o%zj~P(YBH30E z^RRzoVmcY@#_w(|CQQ9((69P;&}Gv1LpS(#qNas|8Krtev9uJ0X0q)R0Th)fje&S` z_5#tmEmC4n+sR6aq}w43+^iX(n(xyelI}2D(~mgV_aNo~IXDV7ZfG+Hx3MnJ(2!C3 z!h`!qchAZCLU=E;c?|AIqlC4Jz8WK`gVv!Dk9Bhy z%^C;@3kKl$_YlDH$dumV*a)s1{t$k>D15zWjM>upsmjXh!`-*MH$lFH_CWdw?Tj0$ zxYRI1;7&dCpLtmZxrNq&S_1ZJR}`g?&weV@gb-aqOaTE1!v_VP(Ut0p9Kxcp7Zr&z zy38IlNJ=`0LrXNhc1CcJ$I|{KXX>C09W`o~oVPzoYO>&VH zzJN4N%(R7chDe}b-iCUID!l=Ct|A5x&uQ*l`eQKTW2q->AE&>54a5C92b<$$W=b^} zNsXGm>#lK>ng0iX=>Jtc09DN{LE_r(nU{T9&!cuWKlw-Gb`7MuWIN z8F;RS5wcr-u)qR0pHW5=W^YVJA3>hiJI!{R_9n*t4e73LxAi%K1R)s$HnkqDJh`?j zZ;`eRZ7c9mQK#j0VcrN*eZOcq5sKp>i3N^aT5F;wr&~nV1gcJR9Gbi{e!jyeRWfS9 zn1qNmg^ZpA(JmoZXfXB?m>G-Ub45SjWXt9-K%VN~v7t4VDK+78#*x-!3)Fh9nza>4 za^16Tn0~>$oNz4dtdqCItMIY^sr)$VU+g?FupBeh_wT)%bz9WkdP&K`H0DB(1=qq5Y-J(U@Zy&y-NgY0Q?f`Wb%-+vI>oD#Nck(N~S+pzhBq}%iW*uC+c zMKyZmmu4{qTIyz|Kih!8k(Kx`HL1|7bOf8Gka4jE-5hG2PnWi+AX+slh6%@bmDjMoZH-18%=e|zFm=(H*>w~@YL6HH z|5S!FjJWtu0)IUoJDWE}a_3`|QDJt&B7yc35u8Vhx%QY~eqy(*2CvFR@MW|_HdyE) zUT-bOq8Y73FlAbyqY=<+zCV-3yfI(C`CLiCD&Yui^*X^er}3=j29O6)5H=c5Lx&DP zkry%0N@8QFO)a!O<{U;=>sl2uR&Tid^Dp#>Cl2Av^cr>SscLH9i+)$oCRxk9mmfNc zrWW44UYNXg)i>1Z>2NFW_UpwbxwMDDv@vFfiY(+zyV**`DhQUrp}Hb;vg=bN$-61X z8nZ3U$FLlyPD-I+b}c?7*wQgT^JhrXFWpp}=P#H;f+dNDJxMcV^_gCawWDXnH&cht z8Z1wSr(&Q=PgS$!$z5<_G39p(pLwz1n+~Tru!aW!m4Z6~WD*>vrZ$T3*_9!&SVv<| zty1$TsKtM+|B|r`JU~SfQQ#8V0p@^WQqXl!i4d&N_EX{5#K$>Ny^=84w*RpXcC|Yf z@197o&lk+Q!tG;1s)|hhC{2ukrOM1G_$2;MPjTwdJ{S6#w> zA1z*y2fH|zhjZGjR0^ZpeQ&}@``Xw!xgYu$dpR`9_oZ29;ul6iqB911$zJIYvyp46i`c`T69-d4%8G$8B{N5w#pZ ziuQHsmvoWZ!%o0cuis85oj;j>UDdX=C6VW}Mr&WKUPG5}*VFO+Gt;&XSbztyh5l7? zcu7?GQE1iv$AYBeD>}CCb`FtR-^MSf)`GpZwzA8%^2+;wNYKDm@;NT5zREve@{xq!tS2uKx+ug)ux-@#1#LDtM0HO zlyK~z2A->@vL)aX(Uqt=AAI7LQ^-;`bpg&CSc&{YAM`Z0j8sFTd{H=@wL|-!=9)Nndph4N<;Pk>2ms;wq=+_35*|Nuna#-|ypBR!-a$^f&D*sP`9r~+&P$qG zKc;ZyBx5&P16_C${IEK6_6x$3CTYCQ>*--V#b@Ginhgv_ry9c_%-u8?iJVOgIu9QG z3czc+$2t$g$nyH0BZ=-eZ4oaZ9+S(tW?VLJIj6v&-=Ljb@4wL2Rg_LRd( z^aXZdSkc5E<2La3^>zqo6kD>D?PH=J`K+N^=WG<6d6=2s)*J~4H)lsg0co@{5~CEw zYFac(a4`5BDB`s6(8>_lTE!lyUcXdKrS-6Jc)0-Ks_RrZ+>JK6nA=tG#JmIU3lSH- zH$o^z5hQMrWxhheCqaZEJU_YhRfasE*x*!iTsD7OW<|!>>rz-E+F!*`knn;>`6SrU zRSq9ptJt_1;Ozv=I)dy31FsS-Km#+|-eXc8n|pPZ+!9ia_$ zzLEUQgvgr_*!j$1P)hQ*7>TK}`O;jX;&t6&_|Iv5kGkBdtk*v~aqG#E*LMiT@b%;U zWAv}wL-_Qz=yxClSw{}C7!*uPZA2U&^2@4X@xkcq(%4in1j6?Jb6db~5dz10cNqw{4~ zQ8+5vU&NJi+n91(AO2`$WGooWx6`mrl*d;$w(!Fy@=Md%B$3q?2-T!czw?Abwdv(r z3rlgzSiKOMx5lC!9P+bdPq&d6Q7k@ZaF>f|i66pUC5Qmx`Z!^;8DqLg@Q4HcF#7!| zxv&f!5KOcaq6hhUzfjzOK;8=;elGXQJ1Ab;SM}YFxuyM|a@h5nN7)K!#xlw0defL*BlGGgwh&Hkt~gSY}LO)s)@jp zHKzAXw6)jrMKv2T8dBt@+=xb8$fo%4pLVH{4gi<5`Bdbe9Zm*mgHW3SH;tRV&Yx|b z@ux!I1P_i~X9FWla0ieEg9bNN0~R~I>XnOWOvLO4cn0MH7Z6mdeVv6O#8!U9mQ{AY z;ze!U+h_eErQVyGQ#KRYjgLNyQkBQRUN>!e17UShL7>T&F~;~CfeQs3<#^eLhNinV@V9LeQ@MgHdgH{2r0>R*Ar zh#ztX;?G#a1ib$D1GeCx=7&cIqo9v@#loE*{QpvN4|4Uc<^G~GWE;;5L2cSNS??_p zKvIT^!zxtAhuaU<#aw3HkOH$rQ45vUmyy4*gVc?MPAT;s7dB0c&l$PwzsY4Vs5(Qk zy@KOyFLS4p_E*M)K0*MVX#NklNPS;$~pSi%JUo`vRlqHS!ViWK8S z2a}V6HFRo3hR)~Ul){r1qH>xhh_^|4ohn~@o39uZVMVry=GEft^~!IC>dlR^-{`#T66F^ z>JP4Vs^9KKnFd^jHf@7OwVVK|?d!)Z7f;$~e?RmoBZ7oROAAHv zgr8F`C@(a4hk1*~&Voa8g2+J}1U~YZq<-jtox(n}PoXEX_)Zb@4M+|An=tyXGd@|Y ze(2vY{UcR1$I+E4I}z(EO!Oez>lF^c^HI>T`>%-4w!vaHI+0S-snMg<$mmk}F>Plc z=KvYm!QjPWwh9Wix$n-urB=n^CwN(T3G?88U7_MagCN*aJuuk9_(RFr2J|B=9?W!( z=Sj`yP24GigT5Vp1u#}KX5{7v{;>PAVY_cwao(G!oA#{GEA`G2{kWiC?0qnf;X9Th ziM{Jh(u`v^0ASQIHckdC9F^s!et?$wg6+V09pD-CaW4|A6yuYz_)Sgf=7^op=i2?J zvkFnoP%Lp2p(oDir^?}t6w!B&#$|}fC6!q8( z{{3+?1w z!I~U%SCs(tvmS|CA;ZtkF{lkmrm>sA+EEFc#%ep&`CL^XHY%WM{q2L+aEZ9B6cl=_ zKSdG0R1)~(2kgRO3azxHNF-y=myF6ylFt3!-x=^4ASoJnvI(dchMK20g}0d+4a0-z z!SAoK*+xscddqkJ`J8c4*UH38y-KS`Pod7Cj6wNLsf;Lz!L5|+q{IhCDmXlN2$e@l zdk7u3&%m3sPd}o14&2P)=X)%q@$A`&HAhkl9J&xj76XfxbQ*Gq(75+kVz(<8PHzVF z`qc`QJjADA#mC-4c8`wxzgJc4Td?rq_gMFfR~W3_GQg$6Z_nT^vge#CU`xTLk4_N4 ziO<6@P{Qlp!A~Q8FHfH=qoq+9%7?9;i2whXiwT zQ~R-ww238)sY@+bl)G&4!|pPc)=fw_O%A+V(Z2~KJUwU3^Guo>UF+q9cn=PL6my^^ zX@SR)Ls@!V%1U6%5lK;1G}*NgoS$B>zaN-P-b(aP{2clYt+l(H%aJbS1Rv!q-r-I3 zM^f!t?qjNg)`deuQoA_g_?LeE)T7K%7ZO@4hQQLTaE3zW7eZ z=1Fpmfnn~Lkc*2NkY=CQz#vTEuBkuwE2HL%;Xk;&$*|GUQFmHS_Pv_np`e=};hP&} zuX@mAX%gwDf|u97v-bXXhoIZ2U)*SWD>_?ed*2-Y2Q)#;zQ`TL6ZlJqoyUYF-!bmY zzPDeuZC)MeZ(45kP>K>r7!eJC9oD4Sr_*c9-y9ZySFwg6Of0v%agSbyo!(I#&r~pw ziQzqFE65MP4d(iDI`+aJLY;wy-=Fc>r_;VwSHliXt<^(nb;a#gK?*X$?_0RW~#_l0vPpu z`?--(S zwQm3#V4yC%)`$CjKY)zPwDw>z#E-qv6cYp8UwD! zuuTD+K{0Ch>KvuoPE-nk7)@B)pwvWMxCkC%rlI51kq&}!#FD55p?eGFc@^Q;T+E_XDhP1v z>OW&S54WsLz?1@RpkBKG&SU^Y*n_Yj-gcIWoNvKw^aBu%O*#1PzAPR+l!xatwl0g} zJzLY*+MB@24jWM;e90W1tm3P?GWg=N(~uy1Xh#bYwt-C9N1z#o3>k$REYPMD$W}cJ zWIPD8LI?@y#+=vtCrBY;q`|1+cx?#F?LOFKz}4<~c{2t{1j3OCo#5N$R&kQY{aemIYqCGfGE+HmLECUiDgh?)|%83q7} z!t~>f{YgX&fj{`(D0ZGKVs&p6@7$b5d9n&gK%`#hzzEZq(iF&+100?7po3d$OgX0=D#MH;O}S~bJ;OYnq`8fg|}5D}e2 z^ltGRS+YPIrO<{p49O3faRZD{?#m6rF%ufS4TOPd2Lm$>9ADwOWpPXt@|ezh2waU) zEp*DFri3X8iW!z9Oy*on7JO(}&_QCJ^We3OzYLH87R{LP^N5oLDJ*E#^K*7C5Jb?> z|1o=w^DZCjCi{kfCkQVL-X*lr|OsY57^}=z}T9# zia#~rjNZ|y(>-ggm9cfP9@8X?0n!FoXoz{rZGktA6KK|m2^(#?8E!d_6Vo+BEFfRi z7@2dizB`J(v;{*fexrxMhnlZ3o_F!sp&TAPn8S|#1b+1$U1*LQDAmH4rxbKrAaHRI zu)*{zh+vxnF;mW$1TWB!g+d%YYvjuTri&ih5++*W25ci#9j*mHYr=$PM#XDX@-19# zqpWyr&c%~Q^O&m!c>ndSC{%s?_-GzQSHW>LijIOHAZ~|Tg}Pp{JTP6wSe{{7Dfkt! zs88Y5^U09Hh9%oE?oFe^NTOB7;OH7;8sy#5tple{{ThJZ!GiAP zTiyU%tA#+90t|&b6pj}Y#h2!s!n1i%9Vy6S{HQa$q8L;}g5uOJ+XD-x_9>u%0|I!S zxb%$OX$%--K(c`%YAB05Hupu)k+AWT<9TGuK3d`yn&T4S&s#^5cXeTXR|L6g07(m}G+aK?^V+6g^X9 zG~`G`FpNH{4J|SakNq%GbKZqb;pY=F244r!Qneb*U~V5YCb5uJdQ0Q&<^h}yq1De| zDnKxojb~3vL;pnAu(>LnTPD2h{jI^VM$1|>e2XQBqSDTibzZq zJXAb|PQwIqu<$k}n)fP{4(Yok0Y}Em_zw>cpy*3{^0qEKcwHLhf{*rui5>k3Z0ZSB zil>Smh(d!CF=Z&7#=!85gUPu#1h+yj=43m=g%L>zVPi&>;c6d}Wat5%XKUkp%?83s z!R2N*T_0JuVxW5JGaiCpLl`f5%V!0a48ZHdLj}__mE1IdgH_Yrod|L-Cn>%?L-{qc z$laV4&B=Drf(|2%v`7XX1*F&|mvx9-~G2FZ|iFC{eWw%rqID2i3{Pe#xwgs9)a*rkxkQ8n! zgdo_42n&i7*MoNpdH@YM?{J#{EWD8$sXK-t1WZZTGnmI;{CF5oAI;)353I&J*QXGd z0>w&zzO;q+U)PHEl!=RT#;-m??Xx`DxhPw2-Mdqiw4jAd)B{ ztOg`zDAJHD&bxM_5f4$&h>IBdqrLHs-nw@Un1lCMDzzU0DBvxg6<9I==Y~?XP~BTa zb?;0^wsTIGZaC@=ey~NQwyd^#y4F}LI$C5Z5fwH}ve*zNB$U>y5!8!#4JL|m6x(Af z@a$X>PaMtTwpD5T(w&{SWmOW-4;8R~q>O_jWh879_pEQiyEmoL))qmv=%ea|FCtTl z`KR%;5LqMq-w-Qn6d4hq6vGbyfMFZqA}YHIj;D~XDg-*LFW5a?M$KciB~3(30i_mV z1&b-mK?K_%9GfWP%R9&MwHGIG*Tyz{_{KK$rY+=3J}iUK6gAM*Y(q-m;8+!zqK_5r zHd+$~EK9)gHFgh|Fjq4mL=4)qAn1*^-C<`ZA)qLVy2e#@UbyHXX_3(*0@5-? zJK`H!XRFyy=p+q0CFeyn3d`Q2STX?Tiy2Jkkoy6EAF2*sQPQ<{9&m?#CgB-(tv36t zEzz~I&*~;((hwvBYr$an5D*OXnVsnIx@c&+h_CLNK~KuU`pzgeu1cWdC_K4$8dHTD zl=3h%Q-M{d;1=~J8@;$XXmLw10ch0fGsBPsA?h7-%yq$$Fd#TO=i(=8@~TK5 zIqXA$Ah9UJc@~dgF-L=jhAj;A8C~41TizjU^YMG0eE0q@-Sedy&QosdTEbEg@XdqW zid(2uD@T=3k0sMB|Loe{$pg-S^>XP@*Nm5oN*JP9rYIrfnjlz%S!h8q)1b0;v2Sh? zohcJN%@(8vTvuU3PZHAw7f&3T!;?p{$P_*Fq$B8Qj=(Ym98cAQai<5pGz0ONf!%{8 z9Ga+NLstx&dZG{_jH=rv!SR7d4(9OpFU;VP138?SaZvNaM(NHb6L+j>!iRUXVSQH= zLJ&N~iBzYS@)=ONg2C!RdZm0oO!)tRqh_OzedUQ+csPa&kl()Av19-)3=F^zf}k{4nw!!sbZX3* zdCB#?C#-nn;Iz(GkJL^khrNlWvR@V^8KPMxsa2%l>HvqG5zLg`P%)_4Ld*<_LpxG7 zx|%};p&z|6gMFupAOP)6HrkRFBmuP`6oYN_6DS7aNdpH*D>yt>L3gu-8&@_VoiGqF z1jch7zVMT2eE+~42*90dQh49?Ry?pRjk`8BU;xUM&jj;655CeXa-4NCBpMpMK< z%~$xw%ai!4$4_B2AK<61>%wR5>q8>aDBi(*mmf1D5tYc40=zg_#Hp-{cdSccLw5{X z0SCv+_`#tpa;4=!&;e23$G;KgLlLB*?70EY%AU-rs(Z>AYt49bWRRg-%rq=vlEQ+q ze8Xclwl_p9AYqd!vVJ~UR@J#mkMj}=sA0(iSi;#*EmX^J^@OLqqpk00Ke+GI;o&i7 zaDZGRjU?6~(kSV~*A)<+z^ZsWL-pO|3}-%hD0}n$a9Hu&gD5blgJG39x&p zfZao3$}kx*kcydzMI^vLp!Ga=e>@^FllO3Px`y$BhjkrM#4L#uQ#E{R?;M^yTENOS z8}HfDf(N&@;D!}(tmufMJ8h#qVIXD-1PUR0aXrzXbz>nLsJH>1IGn|wJ$4GOjFoW1 zs#g5cJC@!L^7XsOTY-( zgbkSR*o&66$5YPCXx$44Py80ck^#6x$Q;f%aCis-p0D`T@2eXkdtNCG6i+xOJNK84 zw~y2^7L2quWE)0vWvclux>FXqn=Lr5f@a3@wis?&l}61A@c5xw>^we)>7s|2WuP-< z!&)RK#>}t?Fo=+=26%2D^cu1yA5R`F;IYGbZ0L#NH}C1jy&KbLjvFY~6iSXlr5d1G zQ*eDgO`{L>H+q8}{K>;v{Kb!l@$9iV#3C{L#=HCRfg9RT?*W>x4`8mhE!P>0_Kj4q zbD)T2Ef((G)QpzaD2Ar1`1-Ca#^yQ^_?-|O#o3988-l-~qGQP&%FGnT9#&QFOCNgR z0|$>!A2&zJ6Y*hxJW51%oMNzq2|1sW!D5ZM(~cZwYnX_bqryalqN2p5#E3hEAPAnp zTd!LXz>)#D)R=$De!g=}p?Cc@&gW+Db{tx1px@|B-pwg{8C6u7PR?d9U8v!@WeFss zVQkh5!XErP*SBDOcM?OhReWdnG+sE7gRdC9=_tC>5g0fC)X+kkCIeDmcg{I^Gk@XXOU z7>0%S-Pnzf-_nV-9T7NwoeS_)M5DGLkarYb7%bxGl!IGWC2`}*B%(rM&rk{9*4MTA<- zG$O);Zg>!{;|bKOCYgyqn#fn$40K@5L}re%iwT4T1#c-YV95Yn27KZZpIEkM^3*Tv zJMhYXEEdd-No#AQHMSi@Hfc5}X10(QC`?zTQS&vnFHay9GvF_3_F35;!^WN@BBp^C zPUf&{AcqsvWhf2wq-}J!$KWds&)10C5^Fo6Sk_`=ZD$PkZ%*Up6-oT?P#)jdokheH zSlbyzP$%Zl91?W|N`(bJhCpj`1o5be!RZSA`pHrJ<>RMtaI^%H2723?@V`CKhwJ+i z^Auo~5a>=v(BBqC%rjG{BNYfDbfqjTOIxV<3Wg*k<0ewc z2oeb!PA$N}(L8>*KZAdMaT@=;YYfA4E<85TnNHwmZtBDbx3{7tZX&4H3M`1SV1DZm zvjko`RmMw0Wmr<+BR968t=Y!QCkuGwKpDf?Rv2m-2o}zT-*54v)vVy?8D@4~^8C_| zQQsR(PEH1y%tUd|clHea@mK$JsKzxXugh&&Ki?cf6iqS#i_CfECSY;RM130okU@ea zq+qSgIaQ4M!arE^ym7q6ynrPGa0&3UKl`&5QNHJEU;Enov(uGdE*Fds!ENt}SzFw6 zbPY*il4h40F0)dAWkevQflOrr422afHhR-`7>!3rr!6I+v)RUmo+J!IVlwaIz-SQ% zM~fKCIuIma8UltS#B7O{q=lx40o#@s&ARyG$HvjwWTNIXOoQ;QO=$=S1RBVeJq*p1 zaCkV67fe>F)&lZ`mQM6b6pEO1w3(R7Ed14C{_DmQX0fzYVllBfYeCIGou#F1X@>Kc7wuW zSm^Q;0O*hZ=8t{l_=6i)Y#5xXO{+04+gc5(>7vChn=bp+;{bA4G5||>9f%LyeRpbPX85{d(fwFyF8B|ng4kl}l}2a$b}wePTZ(If z;gcYv{^k?_X{f*ew1H^U#i8*G`dTG6bjM&&gXTM=%~qPx6g6Civen`kM`yju7NIQyDvFavPClE0>AwWi8}PyOlKW4pfx zg@uBhMzqk#%w?v3=B}UFTXG9C$4i52%6_#uCL%_&ks>LK({y7N3&LtvWJ*KFq(v2W z?Fny275wrE1`psZloDJr02hYSp4#o(H?1CpSD_=nnd}rQMGtMs4d`rLfr^*KoofldaBDj{l2)iO(3pf*c>sna7*gQC zSOrfUEub}S;6ppw(b8<=`};EZ@nMCjTsxxF6HXzYPbc3(je+7ao3?+vyS@AQgD*{$ zUUfej9)Wpy@UVMx|IGvIR;@a+d*(o2wl>#mvT631o%PkvuhofQKoCQNVZkB?K^w<) zey%xx7-bZ$^n-V?uw($<90V4<1y*nF=}R|9K9tQ=|5ZLm?+t3rt5f#%ktTZ`ESap+ z2ywkP=(P`f*e_IHQEb9A2{WY}l&)e;M;y&Dqkh792N>WmSl5-Z(cc=yoC8c2eAHYY z<(k5DDL}`{>o8g(d}r4X9)9*Xm>Chv#KDmqzWDf2eCa1+*zxY4!N-2_m(kJFhrRpu z;o#wYn4Qgl+%BZ-&4@%>F;gDIEvpnhyrUU6u4tMMqJ>R(uX6wEqNnAW!XpQA7|FW0 zd36%^Zfn6r#>IE{&fwr^9JSgqm`Ket{hWIz?*dmxz!OguaM)WC$3i)H=%DnrBWv)UMBfLYV4?@ItcgD54Ey3FOsteUG%@$3Mq z7`W08;Kjm{0XTQO`t5@D{#X~-zq3~4pL2@xBhW4P*ywMLinSsZS*C0wLCj1*Fu(B6 zT!=#Ry#HXp5DCaZQxekafl0jp zS72e!3hWp@-$zcPnM z50){N>wv+%AU4C}oRR$Fjc)@H5U3&;l@qRga%X;0XYj_Zx%kr4U-Glr+(`5CmTcZB zM(4c3swRp@QnCrAu%K9xcvV192+dIuVNZLaz!gyns@baRyo|Sqw&0QhICl^LFf)Dg zn_o;XTef=B>`d;x%C$ZvIR3Mwy89!v3dzU@6_0c?K^cm@kcpop&iry(eDJyvUv^i!HrzbTnD8O@h*kh(MSS=#XA~Lsta0X`=`NJM~CvbXMGCq+LA`u)%ey+8SEOe zP;+|`6)mVA=Jm-xUjH@#00LcsqS8s<7=6Anhl$sG;B+wRHT~7O@^Ihk{)yq@a8J># z^mQ6(t3}3{A;37jqfi6T@W`SF+`x&<`Q>1i=XOJ57H@%Az>)ztJHik(z|2ga{MAqP zj*U+I{OI`5Z+ex;&s*r;6q6fdI&r;9*j*4p2&Jlmi0g02b0?};aBdY0G((bvqsB2X z?O?}>1bUloxB;I=#nli5^%Y}FZvqku69o;AI?)taf!%v{PA;;oSf7FDJh+bx~kpz zm|(*T2v}2_Oe+VjHRVnjV`AnQd>lhVx#SwgQakYLqrpwB0pPcO>tC(hym{HZ6BE-9 zYPabwLVvQ^>a${Ik2Z}I2qcsa2=#@3As`|sr6EK+Y~wl{pMDu%duaxy(S@x&F=Q)# zU09?3`TBqTK;hk+TVPuffBe`C#&Q8Vnr=Zy!a%JuhJXI2NAd8(-+?p%-&b%eKyS<4 zh|3KqyB>1RZp3sB>tYgl;i0Qb<5PEZV(ao4h^W5!Uw^Th5^w{?iJ2N+9xCI#Tbr@E zJBo>ti=6`{9G#B9KpRXMgAOi2a~(?nAg6k+LTdm*h99Db9@3jOZ93M|+Vk&D%#HkE z!j0Y%GosXGb-+{ZX^KMxg3=x*5k;@vnOcL=?V0werwYUFsSCe|D~lx$;I(K3_!t2H z*&qH{*S@1qzi00&FaKgG&mYuY$4wEjI-RuE8&Rv9O_2nVB+X2V1AS+6`Ol0+O1caX zOaKx1T*73bfMkTRwj++HCBpiEdL>`O9akLk{!|yz>3|&nYo*yXS`}<26oo$Dqdm-4K?;LDg_xa3G!xK-^GqhAe)oajo!mL`f>-lv{az4suQhx9dRyXYsX-r%h>$QynxiV)GV9De z>$_?k*EnU^k^u;@c(pPB+;`u79k#7^JonNI@2`~fFV!lsdkwX0dE8uY#m#;lF*~#% zgP2$_`*n};%@9+bc_>5xYXYYjWdc8UYbVCDH9WjGhn*(`q+ShDDKHDryr*=& zi@$M;2%4)1{pO>6!XYcD%iR# zftG|(FIZVv77cG8l>P>8UEK_W7=_v#N@@zO3Ls#>^Q*|$hEVqRqeYakDb|AKL=?r? z9E|iVK7D%!-n+FGZAlY(Cx9W(T({6zZ4K_j<1;mUb59n+&a2Z;o1|B~$hwmS# zVQ{(?t@awQmSE`lv0ljhD0bj;VXzd8KC2uIE}FRW3eJt49CK7Om}CiS%9*`&v$c}r zG6D}gpXVTAvLUn&aL&u?vT!B~(mkksKXZ|9{AI=4-2lk?j{<;CeBu*L*=+V#9)9$z zzdtio_?T2(Ym(LtcGB92nAO2j*kA@Nl!J$_-V0F_J{K?;w$Ta=4|C2W#&RxhTA4yR z7IO9LS2g3*(-m-hjqCdo*xHi>aez!|5;8UoEk+SD%UIcxMkJzi+q`lK3--{u{KKYwx(!`T|{-TQJ zQ$!dfDXbUcMu3>khjQx8U}2Fkz~NTF*T7V90?dRJZ4q>(Ot}66O=x2)u$Y-A8Ijo7 z9l=ej66k3HnxhKMF&`~S4}Bd9x39DD;Tzd}DV8PaM|B7J3mCE5Kau926HiZ;cp01qy{z${5}0Rxi*10Pw4R zffB}?<9YYBnW;o8S`;LSu&$Vh;lm)JW|`oV?y2;wpW9#doxQk*YXaUb2H@3ud}e0r zhfjQON2xUZQzwVUKJJvQ51G32PMemuB#gC2%vc6XrdS9AAR>l-RVCl$=?7`N*_jyv z5dan(RmMabk zL?o{($LFZ_3Y5xShDYI&;O$}n005u;>}M^lOC6@E`~URM|NO4voc~L{EB_b28ok|6 zJ#9&I6O#5iSTcoh;d6cAGc6YTxFR41YXO1wAeAYluvZjZqbG+&;JMY3H& zgmD7L4;OYiVWO`sf|VU{tm=qkc}oOMwgFewwfiXK89dwKp9hEP#mT6|#;zFmrEQ$b zy7bkTvb^(zgn>1P8yysA4G`)iqZeub!Zq%51&XsLwLSifQ@SVy0Lax`*A3H@gKzqLR~T<~13(BpS-E4!jz|y$n(9+7_2vBI(EuO4_Sn8i{&$9;1=nx%>-%@w5A?lp8bz43Lh4Bw;L{ zN4{D{ThhXcbcBf-Z7r{DZ*92puCGw71*kX*m0EyGO~DHkh^QXyJ1>d7dLKi`E)=&6 z%oKe*dMHQ#@WLFT#yUpO0pB-C2z_2Gy>EO=!`TRQ30f46i`e)xK7{@jhn2aer0 zbn3+22M+9CZitR#!de^aiuDOoq#(#5s<-BbI3Ka;%ZY^^009$8xfxmq*gtjxpMPco z(TK!N%M*y0gsQ6{1*FhmN5h(QVy42{#@x{KY+ zOAS8lj0+CS=^qK-oC1nHcq$7wn1x|gp+)Y9uY>9SmG^zi;Y3j1}$lw4; zO8QAeEt|}4w8s+2RF@3E<-~vaFaIk3&2K)@Ha$1nUM)Kvp6hr0-@oy>9$Pf6hm2k) zIl0+TQm~G~q!vU)2W%syi6k^LF$ctT0f|?MY+ZuU@@pJ>UbMAXV7Xaj3<%I1AW#(q zx&#PEY1UarWz5$zV^wcvJkg}~#muNvb&T7dK3@2EQ^ZI~-HsbqCt*oKphEe}R|nl1 zi(e2BwL{?$KL}$4=gQ0jgls^9hz(Qo!LcfRb59NjM%{zLihrl4vn4ltYWIJ1RmP6! z4h_h9%k$Z(zs_w+8O%NlXcbFX-lDSn3yT3X@F-l-W$w-eg~yJ$gTJxD?iMy;3h+n~ zku(ey<%roN;_2>I*)y3LnZ79Jz09~441m1*?tXJ_j-%CTkjUqYao<;oFMs(*D{D2q z*{>zGk&0{+Dp>7QHGCaI#OOrCYS+z?uD}pB1VEZyp%D;kpXQl(F8X4xztI;5t3e

{{%p|=CQ4dnXAHA?sHx4^dCS(#&wcZoM~4d~ z04U&|+i!U8z`)qbZ|}{#Lkh%fOJHkne4b~37cDxjN9!BIaRVLZMCWS>xG}uf7a!&Y zgC?Zrshpy}e_@869W3QazWC>fp?~;qAOHA&X|?tp`0bjSSZ;c4NJRQr=~{jLU--O- zI)#cE%1qohhbAXuE#iMxGh)Ld2l6ZO zj*s8FuMg|Gq7af01PgWdT#wo_0n;TP-+DOxKK9Xymu^o+S81Rsa1rO9;X?~{m#<2c zpL_C>6y#OcZdmb3b~OL}f!fIXTPT@cZucq&1?eL|QpS-C;>pt7$vyx!0OwK+;!@)3 zFaT>{H`NgDjwjp6>{?UIS2jj1xlsnes>xGcYv9ku4BZ^Fjh47&rDDxS%4lhdGLZp5 zKtO_op$U-8ZoN>a{-7~6q-q*Xo)Dr|vQP@xD^mo;uYUQfB_eutlzF}hC1ska z@qA%Zm){gKVB^rJ;y-v~g#M5B^kHLn6s81xU5_vbz?6hn#;W+zbJG~gxX=s?&N|4H zJbditc2sH#ibFYZoPMRynh|J5SBs5(gC+kTUYa!@IWXt@BJ%&nN&e5f9@szm#0$Xm z^mOf>d+z+w$&<%#2~@VD>QCy3NC{2)G>_y>%|8GTL$THY`|iEBZLNOwZ-(CV@!klT zOlf*n=boC>xqI@cv~;r~i-?tQMNCGKph(gpdj(RkQCKnnX9t72Z$#A0AZ6R_ovtg_ z_!U}HtNF{O3e+x?+bNCaE>otuA{0+Wj0l(v5ZRCvg%lAMWCv2lSdbPP3SgfYESUW| zBQ;^ZME6ZSXuROYpSIYEL*0nRvBmtp9ZbZmNV5+>5uob?A1-`V;+iVCP-T~8P>{l( zCaFhF!yl^orJ-_dEUQ`1NMK_5CQMB4La}kiT5dj&H_uA|oEEvHk?L%>bmje>)R9_i zE$5u7^4{Tt^o3`p@aa1{aYJ7mEPz0T27nnD%+&Dou_Au$9bKq+3NH_r@z~)!-gjMV zDDS0C-#Ta=^5YpKIATe>cp|61wmWY=b-a|BbLp!cZRXz|IBfK8!!v~e ztziDhi~s>w*i)4N%JUU!zL2^mC@8q7OnY3I3^+dpoy%$?7>-3Tv}#Ms;I2pK#u_JA zE-p>FO|n`@>%-=N)i#h882YL08l*$7_d^V zOGE)qFYmsX;2rPZaq{Rt9C~IF6B{zBV|_PT;cx{}5#gwaMU>)BTrJ-8dE!C_EqZ&m z_E?PTA)T#}m=~Ry@h2kY$$huq{j*2D{`Iey0nnzK`r8VbQh%$cu3@sbC^vd5*uDXQ zXsXpDOxX%D+7LH7lx;QnGHQ`VjRFb;u`d)C?Enl87(~R403L;FWYNv0)BbpRTz^qi z?scCz1~Z2geh@^Ynb=@Wf*a{Mf)ZN$BG3+NuCT8i1}P?kS!gftbT!LV%>-PSbyYUQ zx-f1gG1Sx~k2l%Yv4K~d`NdwH17^qO7T<@)_FLmTdd!pY)?N<$+hT!@c3d{t934msT01JW^N_(W)gVr7?_Q33d*##L45*myeT(0H7 z)tswJSwW>a65fm!&ah<}r&6iZsd!84$lezQX8|ar5#*C9z;36Jb8O6c%d_MBL z5ft5R$sqdSHId~qZN!<0p;Q3dxA36(4m`y#;>n|f7|B-gt9SO`{;g?5O^Geb;`qIv z>cx1@LtB%H4c$@Pup)t|Euib8B82gRXjJ0mp`!lU%USuvv7)FbYuJv&eos2ikH7oG z6Ztn9-|zk2A7%dXFIOBCq-XP)18s@scR~mg0sFX+fFJ`fg;GXD2W|zxB`(}Zzq{vz zK8gdAmFZh2YVFM(k!CiOrHG}J(u!Qr#auzWDFg6{PyEZK7k2*WQ!D%D-m_wb-_x89 z(Amb=vbBhPdu!J}{2i}ja3pr`+>FrNuIa@O>vRQ3)g}8*VF9p8nEEZGM1b^`FLY z7hL%ZcUSw->}R|UHYa+vC)NfA8Pe6hsB_sN=|^$9+>Qj2IF>z*KY3~tFAf*+t_^A2 zusngg)~1jx`$)$OL@fc^lnV?$1mvp$_Kj8W%<&=)j8^5z8E-D<%kNq-`yV01bFYky zoVECc2z=|UEqiA&`R@hD{0m=I6eyyFAme$rEEs@Gk%nUcSoPuV zsT2SAiM@jLsg<1D-ia2L_5G#LLUeVtM5m_aF4Y(=8Qz2e*kSJ4xp(98Wu<#>yxHk% zN%=T<#P+HcN$-Du2|dd^)A96*KmSX)!ZH$IjyTXL1gfGelUWOe04}l5#J*-CK?Fg7 zgdjlzEW#NyNe~MrL$DwsWthzue*AAAEL+)y^gCs?s!Kr^(^1lFuQ6|fFqD3)Lq zDBlaT@&&uTX6;Km@U&)^h+RXV!U8!VRhFce(ZbJYzcA;jV$ow1go#3X3dJ?sk$?K@ zr|=D!#gRz|drmpoSx4^`hWtry zck3fBy|nk`^BL!w4{sWr{o>9a+Y$a`Ef_bXNWe6rthM)=zJ+r^V@t=R%8I?lJvd)B zpz}KA?qA>SBZYy489kDt()AVXQ>zSXC@f!4q@^`EwSG?G={N7qT?w3z0T2k^Ua^^M zY2$5oczQKn^q zq!eTd=$c{}LK39VVTfI52t#Q_1d=4AX^=EDAfQ<4uvA5ABC{R`qCkOVJugQF0Fc&T zB?T#x+GnCbYwc(qIEEx;L`+xvev#dBNlUjP1S*~`maDE`^ca<7Gs=dIa!U&eYuBUj z=szq(UcINv!I!-bYl1Q zoBRIy(H}qa(!|&ZaGne8EC2c{l?_`r9Bqn6hsuSq)t2lwB34QVszwBP9*LUz8t2fP zQ_3sUyr8h?A1@Wc>utg$l-x7p72cZ<@=aZ$olG)dvJhH{7{(!S0o%DNfj1WeP#Thn z3<+F!osTuEixdPvQ$hm(RXiaKlWVrp*xA(AaL^Z_uS$)I=||B zm;I)94TyXlYMPFVjF!=*NoFQMD;hwyqwF(FopX9n{lhgU{AcC54d$%Fv`LLpN! zFn57xxdJ#J1Hb^VY11kv9-lt8XWv}rhV7zv<7UWZYn6*Ib)~1LKzm=bq#;t(x#{wA z>F(pB#}7c`vjyNG;3VhxbDsl!?sMSzK9$b`c&Ps81%%XFcLOMcuzS((Hvu?&w&D7( zalNOJ<3lh11VnG@ZE-cVdrEuG{y+lpHJ#K#%OV|A;1USNYYO@6x@7a)B~6T&ief!h ztIcYqdZhfkHAnfUDyIH2JMu+lMMPYSM96^|DgFMR{LSJ8_NM2cQaP3Pw0_Ep;FFq) zsCfl#NsBo&PUn~rXk>CUEA5als2DL&s&4`=_1;?oP-By0GnSUein?-LmAq)konVlR z*b!WV?e*tv01hAiy8n@n+<)xlU8x^Fx6@s2Sfc&98yvg6RbzHm;KdhWc zhs^1fwWnzzz8O6I^su{bUFSeFCQqqaw%hZwGGZ=gr5%K_eCKEY7+?-K&<+WM3y~;F z^*!39r~!B_YAAYfbs)>d`|`RRRjeRMkPyN^XD4BL`ohm~8S!Se0Q}GY{G+)WZg|%> z4jc~J<_eX&jvhDLS9AyV&?(^@Jerspn@B#tZqxF=+JE4Hdx^$izdDaVxyK~k2I#Ss#V4V-t⇔CJMB}0P@iUE=LSt;rMG% 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 literal 0 HcmV?d00001 diff --git a/contrib/icons/32x32/website.i2pd.i2pd.png b/contrib/icons/32x32/website.i2pd.i2pd.png new file mode 100644 index 0000000000000000000000000000000000000000..922846c677ef6f5d5d267feed97d699b521b0f9f GIT binary patch literal 2890 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 literal 0 HcmV?d00001 diff --git a/contrib/icons/48x48/website.i2pd.i2pd.png b/contrib/icons/48x48/website.i2pd.i2pd.png new file mode 100644 index 0000000000000000000000000000000000000000..4b7c81ea300412d4c941ad64c0e814dfafd4bf84 GIT binary patch literal 4910 zcmV+}6VdF6P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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

S0b{Lv;K! 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 + + + website.i2pd.i2pd + website.i2pd.i2pd.desktop + CC0-1.0 + BSD-3-Clause + i2pd +

Invisible Internet + +

i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client.

+

I2P (Invisible Internet Protocol) is a universal anonymous network layer. + All communications over I2P are anonymous and end-to-end encrypted, participants + don't reveal their real IP addresses.

+

I2P allows people from all around the world to communicate and share information + without restrictions.

+

Features:

+
    +
  • Distributed anonymous networking framework
  • +
  • End-to-end encrypted communications
  • +
  • Small footprint, simple dependencies, fast performance
  • +
  • Rich set of APIs for developers of secure applications
  • +
+
+ + + https://i2pd.website/images/i2pd_qt.png + + + https://i2pd.website/ + https://github.com/PurpleI2P/i2pd/issues + https://i2pd.readthedocs.io/en/latest/ + supervillain@riseup.net + PurpleI2P Team + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/website.i2pd.i2pd.desktop b/contrib/website.i2pd.i2pd.desktop new file mode 100644 index 0000000..33cb321 --- /dev/null +++ b/contrib/website.i2pd.i2pd.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Categories=Network;P2P;Qt; +Exec=i2pd_qt +GenericName=Invisible Internet +Comment=A universal anonymous network layer +Icon=website.i2pd.i2pd +Name=i2pd +Terminal=false +Type=Application +StartupNotify=false +Keywords=i2p;i2pd;vpn;p2p; diff --git a/i2pd_qt.pro b/i2pd_qt.pro new file mode 100644 index 0000000..4c5084f --- /dev/null +++ b/i2pd_qt.pro @@ -0,0 +1,184 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = i2pd_qt +TEMPLATE = app +QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-deprecated-copy +CONFIG += strict_c++ c++11 + +CONFIG(debug, debug|release) { + message(Debug build) + + # do not redirect logging to std::ostream and to Log pane + DEFINES += DEBUG_WITH_DEFAULT_LOGGING + + DEFINES += I2PD_QT_DEBUG + I2PDMAKE += DEBUG=yes +} +CONFIG(release, debug|release) { + message(Release build) + DEFINES += I2PD_QT_RELEASE + I2PDMAKE += DEBUG=no +} + +SOURCES += \ + src/DaemonQT.cpp \ + src/mainwindow.cpp \ + src/ClientTunnelPane.cpp \ + src/MainWindowItems.cpp \ + src/ServerTunnelPane.cpp \ + src/SignatureTypeComboboxFactory.cpp \ + src/TunnelConfig.cpp \ + src/TunnelPane.cpp \ + src/textbrowsertweaked1.cpp \ + src/pagewithbackbutton.cpp \ + src/widgetlock.cpp \ + src/widgetlockregistry.cpp \ + src/logviewermanager.cpp \ + src/DelayedSaveManager.cpp \ + src/Saver.cpp \ + src/DelayedSaveManagerImpl.cpp \ + src/SaverImpl.cpp \ + src/i2pd/daemon/Daemon.cpp \ + src/i2pd/daemon/HTTPServer.cpp \ + src/i2pd/daemon/I2PControl.cpp \ + src/i2pd/daemon/i2pd.cpp \ + src/i2pd/daemon/UPnP.cpp \ + src/AboutDialog.cpp \ + src/I2pdQtUtil.cpp + +HEADERS += \ + src/DaemonQT.h \ + src/mainwindow.h \ + src/ClientTunnelPane.h \ + src/MainWindowItems.h \ + src/ServerTunnelPane.h \ + src/SignatureTypeComboboxFactory.h \ + src/TunnelConfig.h \ + src/TunnelPane.h \ + src/TunnelsPageUpdateListener.h \ + src/textbrowsertweaked1.h \ + src/pagewithbackbutton.h \ + src/widgetlock.h \ + src/widgetlockregistry.h \ + src/i2pd.rc \ + src/logviewermanager.h \ + src/DelayedSaveManager.h \ + src/Saver.h \ + src/DelayedSaveManagerImpl.h \ + src/SaverImpl.h \ + src/i2pd/daemon/Daemon.h \ + src/i2pd/daemon/HTTPServer.h \ + src/i2pd/daemon/I2PControl.h \ + src/i2pd/daemon/UPnP.h \ + src/AboutDialog.h \ + src/BuildDateTimeQt.h \ + src/I2pdQtUtil.h \ + src/I2pdQtTypes.h + +INCLUDEPATH += src +INCLUDEPATH += src/i2pd/daemon +INCLUDEPATH += src/i2pd/libi2pd +INCLUDEPATH += src/i2pd/libi2pd_client + +FORMS += \ + src/mainwindow.ui \ + src/tunnelform.ui \ + src/statusbuttons.ui \ + src/routercommandswidget.ui \ + src/generalsettingswidget.ui \ + src/AboutDialog.ui + +LIBS += src/i2pd/libi2pd.a src/i2pd/libi2pdclient.a -lz + +libi2pd.commands = @echo Building i2pd libraries +libi2pd.target = src/i2pd/libi2pd.a +libi2pd.depends = i2pd FORCE + +i2pd.commands = cd src/i2pd/ && mkdir -p obj/libi2pd obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes $$I2PDMAKE mk_obj_dir api_client +i2pd.target += src/i2pd/libi2pdclient.a +i2pd.depends = FORCE + +cleani2pd.commands = cd src/i2pd/ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) clean +#cleani2pd.depends = clean + +PRE_TARGETDEPS += src/i2pd/libi2pd.a src/i2pd/libi2pdclient.a +QMAKE_EXTRA_TARGETS += cleani2pd i2pd libi2pd +CLEAN_DEPS += cleani2pd + +BuildDateTimeQtTarget.target = src/BuildDateTimeQt.h +BuildDateTimeQtTarget.depends = FORCE +# 'touch' is unix-only; will probably break on non-unix, TBD +BuildDateTimeQtTarget.commands = touch src/BuildDateTimeQt.h +PRE_TARGETDEPS += src/BuildDateTimeQt.h +QMAKE_EXTRA_TARGETS += BuildDateTimeQtTarget + +# git only, port to other VCS, too. TBD +DEFINES += VCS_COMMIT_INFO="\\\"git:$(shell git -C \""$$_PRO_FILE_PWD_"\" describe)\\\"" + +macx { + message("using mac os x target") + BREWROOT=/usr/local + BOOSTROOT=$$BREWROOT/opt/boost + SSLROOT=$$BREWROOT/opt/libressl + UPNPROOT=$$BREWROOT/opt/miniupnpc + INCLUDEPATH += $$BOOSTROOT/include + INCLUDEPATH += $$SSLROOT/include + INCLUDEPATH += $$UPNPROOT/include + LIBS += $$SSLROOT/lib/libcrypto.a + LIBS += $$SSLROOT/lib/libssl.a + LIBS += $$BOOSTROOT/lib/libboost_system.a + LIBS += $$BOOSTROOT/lib/libboost_date_time.a + LIBS += $$BOOSTROOT/lib/libboost_filesystem.a + LIBS += $$BOOSTROOT/lib/libboost_program_options.a + LIBS += $$UPNPROOT/lib/libminiupnpc.a + LIBS += -Wl,-dead_strip + LIBS += -Wl,-dead_strip_dylibs + LIBS += -Wl,-bind_at_load +} + +linux:!android { + message("Using Linux settings") + LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc +} + +windows { + message("Using Windows settings") + RC_FILE = src/i2pd.rc + DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB + DEFINES -= UNICODE _UNICODE + BOOST_SUFFIX = -mt + QMAKE_CXXFLAGS_RELEASE = -Os + QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + + # linker's -s means "strip" + QMAKE_LFLAGS_RELEASE += -s + + LIBS = \ + src/i2pd/libi2pd.a src/i2pd/libi2pdclient.a \ + -lminiupnpc \ + -lboost_system$$BOOST_SUFFIX \ + -lboost_date_time$$BOOST_SUFFIX \ + -lboost_filesystem$$BOOST_SUFFIX \ + -lboost_program_options$$BOOST_SUFFIX \ + -lssl \ + -lcrypto \ + -lz \ + -lwsock32 \ + -lws2_32 \ + -lgdi32 \ + -liphlpapi \ + -lstdc++ \ + -lpthread +} + +!android:!symbian:!maemo5:!simulator { + message("Build with a system tray icon") + # see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince* + #sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS i2pd_qt.pro resources images + RESOURCES = src/i2pd.qrc + QT += xml + #INSTALLS += sources +} + diff --git a/src/AboutDialog.cpp b/src/AboutDialog.cpp new file mode 100644 index 0000000..ac92694 --- /dev/null +++ b/src/AboutDialog.cpp @@ -0,0 +1,21 @@ +#include "AboutDialog.h" +#include "ui_AboutDialog.h" +#include +#include "version.h" +#include "BuildDateTimeQt.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + ui->setupUi(this); + ui->i2pdVersionLabel->setText(I2PD_VERSION); + ui->i2pVersionLabel->setText(I2P_VERSION); + ui->buildDateTimeLabel->setText(BUILD_DATE_TIME_QT); + ui->vcsCommitInfoLabel->setText(VCS_COMMIT_INFO); +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} diff --git a/src/AboutDialog.h b/src/AboutDialog.h new file mode 100644 index 0000000..d462de2 --- /dev/null +++ b/src/AboutDialog.h @@ -0,0 +1,22 @@ +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include + +namespace Ui { +class AboutDialog; +} + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + +private: + Ui::AboutDialog *ui; +}; + +#endif // ABOUTDIALOG_H diff --git a/src/AboutDialog.ui b/src/AboutDialog.ui new file mode 100644 index 0000000..6e66270 --- /dev/null +++ b/src/AboutDialog.ui @@ -0,0 +1,194 @@ + + + AboutDialog + + + Qt::WindowModal + + + + 0 + 0 + 400 + 199 + + + + About i2pd_qt + + + + :/icons/mask:/icons/mask + + + + + 10 + 160 + 381 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + 10 + 10 + 381 + 17 + + + + <html><head/><body><p><span style=" font-weight:600;">About i2pd_qt</span></p></body></html> + + + + + + 10 + 40 + 131 + 17 + + + + i2pd Version: + + + + + + 10 + 70 + 131 + 17 + + + + Build Date/Time: + + + + + + 150 + 40 + 241 + 20 + + + + I2PD_VERSION_LABEL + + + + + + 10 + 130 + 131 + 17 + + + + I2P Version: + + + + + + 150 + 130 + 241 + 17 + + + + I2P_VERSION_LABEL + + + + + + 150 + 70 + 241 + 20 + + + + BUILD_DATE_TIME_LABEL + + + + + + 10 + 100 + 131 + 17 + + + + Version Control: + + + + + + 150 + 100 + 241 + 17 + + + + VCS_COMMIT_INFO_LABEL + + + + + + + + + buttonBox + accepted() + AboutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/BuildDateTimeQt.h b/src/BuildDateTimeQt.h new file mode 100644 index 0000000..139e208 --- /dev/null +++ b/src/BuildDateTimeQt.h @@ -0,0 +1,7 @@ +#ifndef BUILDDATETIMEQT_H +#define BUILDDATETIMEQT_H + +#include +const QString BUILD_DATE_TIME_QT = QStringLiteral(__DATE__ " " __TIME__); + +#endif // BUILDDATETIMEQT_H diff --git a/src/ClientTunnelPane.cpp b/src/ClientTunnelPane.cpp new file mode 100644 index 0000000..fbfa74c --- /dev/null +++ b/src/ClientTunnelPane.cpp @@ -0,0 +1,220 @@ +#include "ClientTunnelPane.h" +#include "ClientContext.h" +#include "SignatureTypeComboboxFactory.h" +#include "QVBoxLayout" + +ClientTunnelPane::ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow): + TunnelPane(tunnelsPageUpdateListener, tunconf, wrongInputPane_, wrongInputLabel_, mainWindow) {} + +void ClientTunnelPane::setGroupBoxTitle(const QString & title) { + clientTunnelNameGroupBox->setTitle(title); +} + +void ClientTunnelPane::deleteClientTunnelForm() { + TunnelPane::deleteTunnelForm(); + delete clientTunnelNameGroupBox; + clientTunnelNameGroupBox=nullptr; + + //gridLayoutWidget_2->deleteLater(); + //gridLayoutWidget_2=nullptr; +} + +int ClientTunnelPane::appendClientTunnelForm( + ClientTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height) { + + ClientTunnelPane& ui = *this; + + clientTunnelNameGroupBox = new QGroupBox(tunnelsFormGridLayoutWidget); + clientTunnelNameGroupBox->setObjectName(QStringLiteral("clientTunnelNameGroupBox")); + + //tunnel + gridLayoutWidget_2 = new QWidget(clientTunnelNameGroupBox); + + QComboBox *tunnelTypeComboBox = new QComboBox(gridLayoutWidget_2); + tunnelTypeComboBox->setObjectName(QStringLiteral("tunnelTypeComboBox")); + tunnelTypeComboBox->addItem("Client", i2p::client::I2P_TUNNELS_SECTION_TYPE_CLIENT); + tunnelTypeComboBox->addItem("Socks", i2p::client::I2P_TUNNELS_SECTION_TYPE_SOCKS); + tunnelTypeComboBox->addItem("Websocks", i2p::client::I2P_TUNNELS_SECTION_TYPE_WEBSOCKS); + tunnelTypeComboBox->addItem("HTTP Proxy", i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTPPROXY); + tunnelTypeComboBox->addItem("UDP Client", i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPCLIENT); + + int h=(7+4)*60; + gridLayoutWidget_2->setGeometry(QRect(0, 0, 561, h)); + clientTunnelNameGroupBox->setGeometry(QRect(0, 0, 561, h)); + + { + const QString& type = tunnelConfig->getType(); + int index=0; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_CLIENT)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_SOCKS)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTPPROXY)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPCLIENT)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + } + + setupTunnelPane(tunnelConfig, + clientTunnelNameGroupBox, + gridLayoutWidget_2, tunnelTypeComboBox, + tunnelsFormGridLayoutWidget, tunnelsRow, height, h); + //this->tunnelGroupBox->setGeometry(QRect(0, tunnelsFormGridLayoutWidget->height()+10, 561, (7+5)*40+10)); + + /* + std::string destination; + */ + + //host + ui.horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.destinationLabel = new QLabel(gridLayoutWidget_2); + destinationLabel->setObjectName(QStringLiteral("destinationLabel")); + horizontalLayout_2->addWidget(destinationLabel); + ui.destinationLineEdit = new QLineEdit(gridLayoutWidget_2); + destinationLineEdit->setObjectName(QStringLiteral("destinationLineEdit")); + destinationLineEdit->setText(tunnelConfig->getdest().c_str()); + QObject::connect(destinationLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(destinationLineEdit); + ui.destinationHorizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(destinationHorizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + + /* + * int port; + */ + int gridIndex = 2; + { + int port = tunnelConfig->getport(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.portLabel = new QLabel(gridLayoutWidget_2); + portLabel->setObjectName(QStringLiteral("portLabel")); + horizontalLayout_2->addWidget(portLabel); + ui.portLineEdit = new QLineEdit(gridLayoutWidget_2); + portLineEdit->setObjectName(QStringLiteral("portLineEdit")); + portLineEdit->setText(QString::number(port)); + portLineEdit->setMaximumWidth(80); + QObject::connect(portLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(portLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + /* + * std::string keys; +*/ + { + std::string keys = tunnelConfig->getkeys(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.keysLabel = new QLabel(gridLayoutWidget_2); + keysLabel->setObjectName(QStringLiteral("keysLabel")); + horizontalLayout_2->addWidget(keysLabel); + ui.keysLineEdit = new QLineEdit(gridLayoutWidget_2); + keysLineEdit->setObjectName(QStringLiteral("keysLineEdit")); + keysLineEdit->setText(keys.c_str()); + QObject::connect(keysLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(keysLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + /* + * std::string address; + */ + { + std::string address = tunnelConfig->getaddress(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.addressLabel = new QLabel(gridLayoutWidget_2); + addressLabel->setObjectName(QStringLiteral("addressLabel")); + horizontalLayout_2->addWidget(addressLabel); + ui.addressLineEdit = new QLineEdit(gridLayoutWidget_2); + addressLineEdit->setObjectName(QStringLiteral("addressLineEdit")); + addressLineEdit->setText(address.c_str()); + QObject::connect(addressLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(addressLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + /* + int destinationPort; + i2p::data::SigningKeyType sigType; +*/ + { + int destinationPort = tunnelConfig->getdestinationPort(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.destinationPortLabel = new QLabel(gridLayoutWidget_2); + destinationPortLabel->setObjectName(QStringLiteral("destinationPortLabel")); + horizontalLayout_2->addWidget(destinationPortLabel); + ui.destinationPortLineEdit = new QLineEdit(gridLayoutWidget_2); + destinationPortLineEdit->setObjectName(QStringLiteral("destinationPortLineEdit")); + destinationPortLineEdit->setText(QString::number(destinationPort)); + destinationPortLineEdit->setMaximumWidth(80); + QObject::connect(destinationPortLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(destinationPortLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + int cryptoType = tunnelConfig->getcryptoType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + ui.cryptoTypeLabel = new QLabel(gridLayoutWidget_2); + cryptoTypeLabel->setObjectName(QStringLiteral("cryptoTypeLabel")); + horizontalLayout_2->addWidget(cryptoTypeLabel); + ui.cryptoTypeLineEdit = new QLineEdit(gridLayoutWidget_2); + cryptoTypeLineEdit->setObjectName(QStringLiteral("cryptoTypeLineEdit")); + cryptoTypeLineEdit->setText(QString::number(cryptoType)); + cryptoTypeLineEdit->setMaximumWidth(80); + QObject::connect(cryptoTypeLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(cryptoTypeLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + i2p::data::SigningKeyType sigType = tunnelConfig->getsigType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.sigTypeLabel = new QLabel(gridLayoutWidget_2); + sigTypeLabel->setObjectName(QStringLiteral("sigTypeLabel")); + horizontalLayout_2->addWidget(sigTypeLabel); + ui.sigTypeComboBox = SignatureTypeComboBoxFactory::createSignatureTypeComboBox(gridLayoutWidget_2, sigType); + sigTypeComboBox->setObjectName(QStringLiteral("sigTypeComboBox")); + QObject::connect(sigTypeComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(sigTypeComboBox); + QPushButton * lockButton2 = new QPushButton(gridLayoutWidget_2); + horizontalLayout_2->addWidget(lockButton2); + widgetlocks.add(new widgetlock(sigTypeComboBox, lockButton2)); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + I2CPParameters& i2cpParameters = tunnelConfig->getI2cpParameters(); + appendControlsForI2CPParameters(i2cpParameters, gridIndex); + } + + retranslateClientTunnelForm(ui); + + tunnelGridLayout->invalidate(); + + return h; +} + +ServerTunnelPane* ClientTunnelPane::asServerTunnelPane(){return nullptr;} +ClientTunnelPane* ClientTunnelPane::asClientTunnelPane(){return this;} diff --git a/src/ClientTunnelPane.h b/src/ClientTunnelPane.h new file mode 100644 index 0000000..f6bf437 --- /dev/null +++ b/src/ClientTunnelPane.h @@ -0,0 +1,126 @@ +#ifndef CLIENTTUNNELPANE_H +#define CLIENTTUNNELPANE_H + +#include "QGridLayout" +#include "QVBoxLayout" + +#include "TunnelPane.h" + +class ClientTunnelConfig; + +class ServerTunnelPane; +class TunnelPane; + +class ClientTunnelPane : public TunnelPane { + Q_OBJECT +public: + ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow); + virtual ~ClientTunnelPane(){} + virtual ServerTunnelPane* asServerTunnelPane(); + virtual ClientTunnelPane* asClientTunnelPane(); + int appendClientTunnelForm(ClientTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, + int tunnelsRow, int height); + void deleteClientTunnelForm(); +private: + QGroupBox *clientTunnelNameGroupBox; + + //tunnel + QWidget *gridLayoutWidget_2; + + //destination + QHBoxLayout *horizontalLayout_2; + QLabel *destinationLabel; + QLineEdit *destinationLineEdit; + QSpacerItem *destinationHorizontalSpacer; + + //port + QLabel * portLabel; + QLineEdit * portLineEdit; + + //keys + QLabel * keysLabel; + QLineEdit * keysLineEdit; + + //address + QLabel * addressLabel; + QLineEdit * addressLineEdit; + + //destinationPort + QLabel * destinationPortLabel; + QLineEdit * destinationPortLineEdit; + + //sigType + QLabel * sigTypeLabel; + QComboBox * sigTypeComboBox; + + //cryptoType + QLabel * cryptoTypeLabel; + QLineEdit * cryptoTypeLineEdit; + +protected slots: + virtual void setGroupBoxTitle(const QString & title); + +private: + void retranslateClientTunnelForm(ClientTunnelPane& /*ui*/) { + typeLabel->setText(QApplication::translate("cltTunForm", "Client tunnel type:", 0)); + destinationLabel->setText(QApplication::translate("cltTunForm", "Destination:", 0)); + portLabel->setText(QApplication::translate("cltTunForm", "Port:", 0)); + cryptoTypeLabel->setText(QApplication::translate("cltTunForm", "Crypto type:", 0)); + keysLabel->setText(QApplication::translate("cltTunForm", "Keys:", 0)); + destinationPortLabel->setText(QApplication::translate("cltTunForm", "Destination port:", 0)); + addressLabel->setText(QApplication::translate("cltTunForm", "Address:", 0)); + sigTypeLabel->setText(QApplication::translate("cltTunForm", "Signature type:", 0)); + } +protected: + virtual bool applyDataFromUIToTunnelConfig() { + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); + bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); + if(!ok)return false; + ClientTunnelConfig* ctc=tunnelConfig->asClientTunnelConfig(); + assert(ctc!=nullptr); + + if(!isValidSingleLine(destinationLineEdit))return false; + if(!isValidSingleLine(portLineEdit))return false; + if(!isValidSingleLine(cryptoTypeLineEdit))return false; + if(!isValidSingleLine(keysLineEdit))return false; + if(!isValidSingleLine(addressLineEdit))return false; + if(!isValidSingleLine(destinationPortLineEdit))return false; + + //destination + ctc->setdest(destinationLineEdit->text().toStdString()); + + auto portStr=portLineEdit->text(); + int portInt=portStr.toInt(&ok); + + if(!ok){ + highlightWrongInput(QApplication::tr("Bad port, must be int.")+" "+cannotSaveSettings,portLineEdit); + return false; + } + ctc->setport(portInt); + + auto cryptoTypeStr=cryptoTypeLineEdit->text(); + int cryptoTypeInt=cryptoTypeStr.toInt(&ok); + if(!ok){ + highlightWrongInput(QApplication::tr("Bad crypto type, must be int.")+" "+cannotSaveSettings,cryptoTypeLineEdit); + return false; + } + ctc->setcryptoType(cryptoTypeInt); + + ctc->setkeys(keysLineEdit->text().toStdString()); + + ctc->setaddress(addressLineEdit->text().toStdString()); + + auto dportStr=destinationPortLineEdit->text(); + int dportInt=dportStr.toInt(&ok); + if(!ok){ + highlightWrongInput(QApplication::tr("Bad destinationPort, must be int.")+" "+cannotSaveSettings,destinationPortLineEdit); + return false; + } + ctc->setdestinationPort(dportInt); + + ctc->setsigType(readSigTypeComboboxUI(sigTypeComboBox)); + return true; + } +}; + +#endif // CLIENTTUNNELPANE_H diff --git a/src/DaemonQT.cpp b/src/DaemonQT.cpp new file mode 100644 index 0000000..1e45c58 --- /dev/null +++ b/src/DaemonQT.cpp @@ -0,0 +1,195 @@ +#include + +#include "DaemonQT.h" +#include "Daemon.h" +#include "mainwindow.h" + +#include "Log.h" + +#include +#include +#include +#include + +//#define DEBUG_WITH_DEFAULT_LOGGING (1) + +namespace i2p +{ +namespace qt +{ + Worker::Worker (DaemonQTImpl& daemon): + m_Daemon (daemon) + { + } + + void Worker::startDaemon() + { + qDebug("Performing daemon start..."); + //try{ + m_Daemon.start(); + qDebug("Daemon started."); + emit resultReady(false, ""); + /*}catch(std::exception ex){ + emit resultReady(true, ex.what()); + }catch(...){ + emit resultReady(true, QObject::tr("Error: unknown exception")); + }*/ + } + void Worker::restartDaemon() + { + qDebug("Performing daemon restart..."); + //try{ + m_Daemon.restart(); + qDebug("Daemon restarted."); + emit resultReady(false, ""); + /*}catch(std::exception ex){ + emit resultReady(true, ex.what()); + }catch(...){ + emit resultReady(true, QObject::tr("Error: unknown exception")); + }*/ + } + void Worker::stopDaemon() { + qDebug("Performing daemon stop..."); + //try{ + m_Daemon.stop(); + qDebug("Daemon stopped."); + emit resultReady(false, ""); + /*}catch(std::exception ex){ + emit resultReady(true, ex.what()); + }catch(...){ + emit resultReady(true, QObject::tr("Error: unknown exception")); + }*/ + } + + Controller::Controller(DaemonQTImpl& daemon): + m_Daemon (daemon) + { + Worker *worker = new Worker (m_Daemon); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &Controller::startDaemon, worker, &Worker::startDaemon); + connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon); + connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon); + connect(worker, &Worker::resultReady, this, &Controller::handleResults); + workerThread.start(); + } + Controller::~Controller() + { + qDebug("Closing and waiting for daemon worker thread..."); + workerThread.quit(); + workerThread.wait(); + qDebug("Waiting for daemon worker thread finished."); + if(m_Daemon.isRunning()) + { + qDebug("Stopping the daemon..."); + m_Daemon.stop(); + qDebug("Stopped the daemon."); + } + } + + DaemonQTImpl::DaemonQTImpl (): + mutex(nullptr), m_IsRunning(nullptr), m_RunningChangedCallback(nullptr) + { + } + + DaemonQTImpl::~DaemonQTImpl () + { + delete mutex; + } + + bool DaemonQTImpl::init(int argc, char* argv[], std::shared_ptr logstream) + { + mutex=new QMutex(QMutex::Recursive); + setRunningCallback(0); + m_IsRunning=false; + return Daemon.init(argc,argv,logstream); + } + + void DaemonQTImpl::start() + { + QMutexLocker locker(mutex); + setRunning(true); + Daemon.start(); + } + + void DaemonQTImpl::stop() + { + QMutexLocker locker(mutex); + Daemon.stop(); + setRunning(false); + } + + void DaemonQTImpl::restart() + { + QMutexLocker locker(mutex); + stop(); + start(); + } + + void DaemonQTImpl::setRunningCallback(runningChangedCallback cb) + { + m_RunningChangedCallback = cb; + } + + bool DaemonQTImpl::isRunning() + { + return m_IsRunning; + } + + void DaemonQTImpl::setRunning(bool newValue) + { + bool oldValue = m_IsRunning; + if(oldValue!=newValue) + { + m_IsRunning = newValue; + if(m_RunningChangedCallback) + m_RunningChangedCallback(); + } + } + + int RunQT (int argc, char* argv[]) + { + QApplication app(argc, argv); + int result; + + { + std::shared_ptr logstreamptr= +#ifdef DEBUG_WITH_DEFAULT_LOGGING + nullptr +#else + std::make_shared() +#endif + ; + //TODO move daemon init deinit to a bg thread + DaemonQTImpl daemon; + if(logstreamptr) (*logstreamptr) << "Initialising the daemon..." << std::endl; + bool daemonInitSuccess = daemon.init(argc, argv, logstreamptr); + if(!daemonInitSuccess) + { + QMessageBox::critical(0, "Error", "Daemon init failed"); + return 1; + } + LogPrint(eLogDebug, "Initialised, creating the main window..."); + MainWindow w(logstreamptr); + LogPrint(eLogDebug, "Before main window.show()..."); + w.show (); + + { + i2p::qt::Controller daemonQtController(daemon); + w.setI2PController(&daemonQtController); + LogPrint(eLogDebug, "Starting the daemon..."); + emit daemonQtController.startDaemon(); + //daemon.start (); + LogPrint(eLogDebug, "Starting GUI event loop..."); + result = app.exec(); + //daemon.stop (); + } + } + + //QMessageBox::information(&w, "Debug", "demon stopped"); + LogPrint(eLogDebug, "Exiting the application"); + return result; + } +} +} + diff --git a/src/DaemonQT.h b/src/DaemonQT.h new file mode 100644 index 0000000..aa329f5 --- /dev/null +++ b/src/DaemonQT.h @@ -0,0 +1,88 @@ +#ifndef DAEMONQT_H +#define DAEMONQT_H + +#include +#include +#include +#include +#include + +namespace i2p +{ +namespace qt +{ + class DaemonQTImpl + { + public: + + DaemonQTImpl (); + ~DaemonQTImpl (); + + typedef void (*runningChangedCallback)(); + + /** + * @brief init + * @param argc + * @param argv + * @return success + */ + bool init(int argc, char* argv[], std::shared_ptr logstream); + void start(); + void stop(); + void restart(); + void setRunningCallback(runningChangedCallback cb); + bool isRunning(); + private: + void setRunning(bool running); + void showError(std::string errorMsg); + private: + QMutex* mutex; + bool m_IsRunning; + runningChangedCallback m_RunningChangedCallback; + }; + + class Worker : public QObject + { + Q_OBJECT + public: + + Worker (DaemonQTImpl& daemon); + + private: + + DaemonQTImpl& m_Daemon; + + public slots: + void startDaemon(); + void restartDaemon(); + void stopDaemon(); + + signals: + void resultReady(bool failed, QString failureMessage); + }; + + class Controller : public QObject + { + Q_OBJECT + QThread workerThread; + public: + Controller(DaemonQTImpl& daemon); + ~Controller(); + private: + DaemonQTImpl& m_Daemon; + + public slots: + void handleResults(bool failed, QString failureMessage){ + if(failed){ + QMessageBox::critical(0, QObject::tr("Error"), failureMessage); + } + } + signals: + void startDaemon(); + void stopDaemon(); + void restartDaemon(); + }; +} +} + +#endif // DAEMONQT_H diff --git a/src/DelayedSaveManager.cpp b/src/DelayedSaveManager.cpp new file mode 100644 index 0000000..8e17d11 --- /dev/null +++ b/src/DelayedSaveManager.cpp @@ -0,0 +1,3 @@ +#include "DelayedSaveManager.h" + +DelayedSaveManager::DelayedSaveManager(){} diff --git a/src/DelayedSaveManager.h b/src/DelayedSaveManager.h new file mode 100644 index 0000000..2382143 --- /dev/null +++ b/src/DelayedSaveManager.h @@ -0,0 +1,26 @@ +#ifndef DELAYEDSAVEMANAGER_H +#define DELAYEDSAVEMANAGER_H + +#include "Saver.h" +#include "I2pdQtTypes.h" + +class DelayedSaveManager +{ +public: + DelayedSaveManager(); + + virtual void setSaver(Saver* saver)=0; + + typedef unsigned int DATA_SERIAL_TYPE; + + virtual void delayedSave(bool reloadAfterSave, DATA_SERIAL_TYPE dataSerial, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus)=0; + + //returns false iff save failed + virtual bool appExiting()=0; + + virtual FocusEnum getFocusOn()=0; + virtual std::string& getTunnelNameToFocus()=0; + virtual QWidget* getWidgetToFocus()=0; +}; + +#endif // DELAYEDSAVEMANAGER_H diff --git a/src/DelayedSaveManagerImpl.cpp b/src/DelayedSaveManagerImpl.cpp new file mode 100644 index 0000000..bad6fdb --- /dev/null +++ b/src/DelayedSaveManagerImpl.cpp @@ -0,0 +1,140 @@ +#include "DelayedSaveManagerImpl.h" + +#include + +DelayedSaveManagerImpl::DelayedSaveManagerImpl() : + widgetToFocus(nullptr), + saver(nullptr), + lastDataSerialSeen(DelayedSaveManagerImpl::INITIAL_DATA_SERIAL), + lastSaveStartedTimestamp(A_VERY_OBSOLETE_TIMESTAMP), + exiting(false), + thread(new DelayedSaveThread(this)) +{ +} + +void DelayedSaveManagerImpl::setSaver(Saver* saver) { + this->saver = saver; +} + +void DelayedSaveManagerImpl::start() { + thread->start(); +} + +bool DelayedSaveManagerImpl::isSaverValid() { + return saver != nullptr; +} + +void DelayedSaveManagerImpl::delayedSave(bool reloadAfterSave, DATA_SERIAL_TYPE dataSerial, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus) { + if(lastDataSerialSeen==dataSerial)return; + this->reloadAfterSave = reloadAfterSave; + this->focusOn = focusOn; + this->tunnelNameToFocus = tunnelNameToFocus; + this->widgetToFocus = widgetToFocus; + lastDataSerialSeen=dataSerial; + assert(isSaverValid()); + TIMESTAMP_TYPE now = getTime(); + TIMESTAMP_TYPE wakeTime = lastSaveStartedTimestamp + DelayedSaveThread::WAIT_TIME_MILLIS; + if(now < wakeTime) { + //defer save until lastSaveStartedTimestamp + DelayedSaveThread::WAIT_TIME_MILLIS + thread->deferSaveUntil(wakeTime); + return; + } + lastSaveStartedTimestamp = now; + thread->startSavingNow(); +} + +bool DelayedSaveManagerImpl::appExiting() { + exiting=true; + thread->wakeThreadAndJoinThread(); + assert(isSaverValid()); + saver->save(false, FocusEnum::noFocus); + return true; +} + +DelayedSaveThread::DelayedSaveThread(DelayedSaveManagerImpl* delayedSaveManagerImpl_): + delayedSaveManagerImpl(delayedSaveManagerImpl_), + mutex(new QMutex()), + waitCondition(new QWaitCondition()), + saveNow(false), + defer(false) +{ + mutex->lock(); +} + +DelayedSaveThread::~DelayedSaveThread(){ + mutex->unlock(); + delete mutex; + delete waitCondition; +} + +void DelayedSaveThread::run() { + forever { + if(delayedSaveManagerImpl->isExiting())return; + waitCondition->wait(mutex, WAIT_TIME_MILLIS); + if(delayedSaveManagerImpl->isExiting())return; + Saver* saver = delayedSaveManagerImpl->getSaver(); + assert(saver!=nullptr); + if(saveNow) { + saveNow = false; + const FocusEnum focusOn = delayedSaveManagerImpl->getFocusOn(); + const std::string tunnelNameToFocus = delayedSaveManagerImpl->getTunnelNameToFocus(); + QWidget* widgetToFocus = delayedSaveManagerImpl->getWidgetToFocus(); + saver->save(delayedSaveManagerImpl->isReloadAfterSave(), focusOn, tunnelNameToFocus, widgetToFocus); + continue; + } + if(defer) { + defer=false; +#define max(a,b) (((a)>(b))?(a):(b)) + forever { + TIMESTAMP_TYPE now = DelayedSaveManagerImpl::getTime(); + TIMESTAMP_TYPE millisToWait = max(wakeTime-now, 0); + if(millisToWait>0) { + waitCondition->wait(mutex, millisToWait); + if(delayedSaveManagerImpl->isExiting())return; + continue; + } + const FocusEnum focusOn = delayedSaveManagerImpl->getFocusOn(); + const std::string tunnelNameToFocus = delayedSaveManagerImpl->getTunnelNameToFocus(); + QWidget* widgetToFocus = delayedSaveManagerImpl->getWidgetToFocus(); + saver->save(delayedSaveManagerImpl->isReloadAfterSave(), focusOn, tunnelNameToFocus, widgetToFocus); + break; //break inner loop + } + } + } +} + +void DelayedSaveThread::wakeThreadAndJoinThread() { + waitCondition->wakeAll(); + quit(); + wait();//join //"similar to the POSIX pthread_join()" +} + +DelayedSaveManagerImpl::TIMESTAMP_TYPE DelayedSaveManagerImpl::getTime() { + return QDateTime::currentMSecsSinceEpoch(); +} + +void DelayedSaveThread::deferSaveUntil(TIMESTAMP_TYPE wakeTime_) { + wakeTime = wakeTime_; + defer = true; + waitCondition->wakeAll(); +} + +void DelayedSaveThread::startSavingNow() { + //mutex->lock(); + saveNow=true; + waitCondition->wakeAll(); + //mutex->unlock(); +} + +DelayedSaveManagerImpl::~DelayedSaveManagerImpl() { + thread->wakeThreadAndJoinThread(); + delete thread; +} + +bool DelayedSaveManagerImpl::isExiting() { + return exiting; +} +Saver* DelayedSaveManagerImpl::getSaver() { + return saver; +} + diff --git a/src/DelayedSaveManagerImpl.h b/src/DelayedSaveManagerImpl.h new file mode 100644 index 0000000..c9a77c3 --- /dev/null +++ b/src/DelayedSaveManagerImpl.h @@ -0,0 +1,84 @@ +#ifndef DELAYEDSAVEMANAGERIMPL_H +#define DELAYEDSAVEMANAGERIMPL_H + +#include +#include +#include +#include +#include + +#include "I2pdQtTypes.h" +#include "DelayedSaveManager.h" +#include "Saver.h" + +class DelayedSaveManagerImpl; +class Saver; + +class DelayedSaveThread : public QThread { + Q_OBJECT + +public: + static constexpr unsigned long WAIT_TIME_MILLIS = 1000L; + + typedef qint64 TIMESTAMP_TYPE; + static constexpr TIMESTAMP_TYPE A_VERY_OBSOLETE_TIMESTAMP=0; + + DelayedSaveThread(DelayedSaveManagerImpl* delayedSaveManagerImpl); + virtual ~DelayedSaveThread(); + + void run() override; + + void deferSaveUntil(TIMESTAMP_TYPE wakeTime); + void startSavingNow(); + + void wakeThreadAndJoinThread(); + +private: + DelayedSaveManagerImpl* delayedSaveManagerImpl; + QMutex* mutex; + QWaitCondition* waitCondition; + volatile bool saveNow; + volatile bool defer; + volatile TIMESTAMP_TYPE wakeTime; +}; + +class DelayedSaveManagerImpl : public DelayedSaveManager { + FocusEnum focusOn; + std::string tunnelNameToFocus; + QWidget* widgetToFocus; + bool reloadAfterSave; +public: + DelayedSaveManagerImpl(); + virtual ~DelayedSaveManagerImpl(); + virtual void setSaver(Saver* saver); + virtual void start(); + virtual void delayedSave(bool reloadAfterSave, DATA_SERIAL_TYPE dataSerial, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus); + virtual bool appExiting(); + + typedef DelayedSaveThread::TIMESTAMP_TYPE TIMESTAMP_TYPE; + + static constexpr DATA_SERIAL_TYPE INITIAL_DATA_SERIAL=0; + bool isExiting(); + Saver* getSaver(); + static TIMESTAMP_TYPE getTime(); + + bool isReloadAfterSave() { return reloadAfterSave; } + FocusEnum getFocusOn() { return focusOn; } + std::string& getTunnelNameToFocus() { return tunnelNameToFocus; } + QWidget* getWidgetToFocus() { return widgetToFocus; } + +private: + Saver* saver; + bool isSaverValid(); + + DATA_SERIAL_TYPE lastDataSerialSeen; + + static constexpr TIMESTAMP_TYPE A_VERY_OBSOLETE_TIMESTAMP=DelayedSaveThread::A_VERY_OBSOLETE_TIMESTAMP; + TIMESTAMP_TYPE lastSaveStartedTimestamp; + + bool exiting; + DelayedSaveThread* thread; + void wakeThreadAndJoinThread(); +}; + +#endif // DELAYEDSAVEMANAGERIMPL_H diff --git a/src/I2pdQtTypes.h b/src/I2pdQtTypes.h new file mode 100644 index 0000000..c7b1917 --- /dev/null +++ b/src/I2pdQtTypes.h @@ -0,0 +1,7 @@ +#ifndef I2PDQTTYPES_H +#define I2PDQTTYPES_H + +enum WrongInputPageEnum { generalSettingsPage, tunnelsSettingsPage }; +enum FocusEnum { noFocus, focusOnTunnelName, focusOnWidget }; + +#endif // I2PDQTTYPES_H diff --git a/src/I2pdQtUtil.cpp b/src/I2pdQtUtil.cpp new file mode 100644 index 0000000..35a7adf --- /dev/null +++ b/src/I2pdQtUtil.cpp @@ -0,0 +1,12 @@ +#include "I2pdQtUtil.h" + +bool isValidSingleLine(QLineEdit* widget, WrongInputPageEnum inputPage, MainWindow* mainWindow) { + bool correct = !widget->text().contains(QRegularExpression("[\r\n]"), nullptr); + if(!correct) { + mainWindow->highlightWrongInput( + QApplication::tr("Single line input expected, but it's multiline"), + inputPage, + widget); + } + return correct; +} diff --git a/src/I2pdQtUtil.h b/src/I2pdQtUtil.h new file mode 100644 index 0000000..90c3e52 --- /dev/null +++ b/src/I2pdQtUtil.h @@ -0,0 +1,9 @@ +#ifndef I2pdQtUtil_H +#define I2pdQtUtil_H + +class QLineEdit; +#include "mainwindow.h" + +bool isValidSingleLine(QLineEdit* widget, WrongInputPageEnum inputPage, MainWindow* mainWindow); + +#endif // I2pdQtUtil_H diff --git a/src/MainWindowItems.cpp b/src/MainWindowItems.cpp new file mode 100644 index 0000000..c1e1ab0 --- /dev/null +++ b/src/MainWindowItems.cpp @@ -0,0 +1,2 @@ +#include "MainWindowItems.h" + diff --git a/src/MainWindowItems.h b/src/MainWindowItems.h new file mode 100644 index 0000000..a4be5fe --- /dev/null +++ b/src/MainWindowItems.h @@ -0,0 +1,17 @@ +#ifndef MAINWINDOWITEMS_H +#define MAINWINDOWITEMS_H + +#include +#include +#include +#include +#include + +#include +#include + +#include "mainwindow.h" + +class MainWindow; + +#endif // MAINWINDOWITEMS_H diff --git a/src/Saver.cpp b/src/Saver.cpp new file mode 100644 index 0000000..4841acb --- /dev/null +++ b/src/Saver.cpp @@ -0,0 +1,6 @@ +#include "Saver.h" + +Saver::Saver() +{ + +} diff --git a/src/Saver.h b/src/Saver.h new file mode 100644 index 0000000..bf971fb --- /dev/null +++ b/src/Saver.h @@ -0,0 +1,25 @@ +#ifndef SAVER_H +#define SAVER_H + +#include +#include +#include +class QWidget; + +#include "I2pdQtTypes.h" + +class Saver : public QObject +{ + Q_OBJECT + +public: + Saver(); + //FocusEnum::focusNone iff failures //??? wtf + virtual bool save(bool reloadAfterSave, const FocusEnum focusOn, const std::string& tunnelNameToFocus="", QWidget* widgetToFocus=nullptr)=0; + +signals: + void reloadTunnelsConfigAndUISignal(const QString); + +}; + +#endif // SAVER_H diff --git a/src/SaverImpl.cpp b/src/SaverImpl.cpp new file mode 100644 index 0000000..fee2526 --- /dev/null +++ b/src/SaverImpl.cpp @@ -0,0 +1,81 @@ +#include "SaverImpl.h" + +#include +#include +#include + +#include "QList" +#include "QString" + +#include "mainwindow.h" + +SaverImpl::SaverImpl(MainWindow *mainWindowPtr_, QList * configItems_, std::map* tunnelConfigs_) : + configItems(configItems_), tunnelConfigs(tunnelConfigs_), confpath(), tunconfpath(), mainWindowPtr(mainWindowPtr_) +{} + +SaverImpl::~SaverImpl() {} + +bool SaverImpl::save(bool reloadAfterSave, const FocusEnum focusOn, const std::string& tunnelNameToFocus, QWidget* widgetToFocus) { + //save main config + { + std::stringstream out; + for(QList::iterator it = configItems->begin(); it!= configItems->end(); ++it) { + MainWindowItem* item = *it; + item->saveToStringStream(out); + } + + using namespace std; + + + QString backup=confpath+"~"; + if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors + if(QFile::exists(confpath)) QFile::rename(confpath, backup);//TODO handle errors + ofstream outfile; + outfile.open(confpath.toStdString());//TODO handle errors + outfile << out.str().c_str(); + outfile.close(); + } + + //save tunnels config + { + std::stringstream out; + + for (std::map::iterator it=tunnelConfigs->begin(); it!=tunnelConfigs->end(); ++it) { + //const std::string& name = it->first; + TunnelConfig* tunconf = it->second; + tunconf->saveHeaderToStringStream(out); + tunconf->saveToStringStream(out); + tunconf->saveI2CPParametersToStringStream(out); + } + + using namespace std; + + QString backup=tunconfpath+"~"; + if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors + if(QFile::exists(tunconfpath)) QFile::rename(tunconfpath, backup);//TODO handle errors + ofstream outfile; + outfile.open(tunconfpath.toStdString());//TODO handle errors + outfile << out.str().c_str(); + outfile.close(); + } + + if(reloadAfterSave) { + //reload saved configs +#if 0 + i2p::client::context.ReloadConfig(); +#endif + + if(reloadAfterSave) emit reloadTunnelsConfigAndUISignal(focusOn==FocusEnum::focusOnTunnelName?QString::fromStdString(tunnelNameToFocus):""); + } + + return true; +} + +void SaverImpl::setConfPath(QString& confpath_) { confpath = confpath_; } + +void SaverImpl::setTunnelsConfPath(QString& tunconfpath_) { tunconfpath = tunconfpath_; } + +/*void SaverImpl::setTunnelFocus(bool focusOnTunnel, std::string tunnelNameToFocus) { + this->focusOnTunnel=focusOnTunnel; + this->tunnelNameToFocus=tunnelNameToFocus; +}*/ diff --git a/src/SaverImpl.h b/src/SaverImpl.h new file mode 100644 index 0000000..d20f1bb --- /dev/null +++ b/src/SaverImpl.h @@ -0,0 +1,33 @@ +#ifndef SAVERIMPL_H +#define SAVERIMPL_H + +#include +#include + +#include +#include "QList" + +#include "mainwindow.h" +#include "TunnelConfig.h" +#include "Saver.h" + +class MainWindowItem; +class TunnelConfig; + +class SaverImpl : public Saver +{ +public: + SaverImpl(MainWindow *mainWindowPtr_, QList * configItems_, std::map* tunnelConfigs_); + virtual ~SaverImpl(); + virtual bool save(bool reloadAfterSave, const FocusEnum focusOn, const std::string& tunnelNameToFocus, QWidget* widgetToFocus); + void setConfPath(QString& confpath_); + void setTunnelsConfPath(QString& tunconfpath_); +private: + QList * configItems; + std::map* tunnelConfigs; + QString confpath; + QString tunconfpath; + MainWindow* mainWindowPtr; +}; + +#endif // SAVERIMPL_H diff --git a/src/ServerTunnelPane.cpp b/src/ServerTunnelPane.cpp new file mode 100644 index 0000000..cd751f5 --- /dev/null +++ b/src/ServerTunnelPane.cpp @@ -0,0 +1,278 @@ +#include "ServerTunnelPane.h" +#include "ClientContext.h" +#include "SignatureTypeComboboxFactory.h" + +ServerTunnelPane::ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow): + TunnelPane(tunnelsPageUpdateListener, tunconf, wrongInputPane_, wrongInputLabel_, mainWindow) {} + +void ServerTunnelPane::setGroupBoxTitle(const QString & title) { + serverTunnelNameGroupBox->setTitle(title); +} + +int ServerTunnelPane::appendServerTunnelForm( + ServerTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height) { + + ServerTunnelPane& ui = *this; + + serverTunnelNameGroupBox = new QGroupBox(tunnelsFormGridLayoutWidget); + serverTunnelNameGroupBox->setObjectName(QStringLiteral("serverTunnelNameGroupBox")); + + //tunnel + gridLayoutWidget_2 = new QWidget(serverTunnelNameGroupBox); + + QComboBox *tunnelTypeComboBox = new QComboBox(gridLayoutWidget_2); + tunnelTypeComboBox->setObjectName(QStringLiteral("tunnelTypeComboBox")); + tunnelTypeComboBox->addItem("Server", i2p::client::I2P_TUNNELS_SECTION_TYPE_SERVER); + tunnelTypeComboBox->addItem("HTTP", i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTP); + tunnelTypeComboBox->addItem("IRC", i2p::client::I2P_TUNNELS_SECTION_TYPE_IRC); + tunnelTypeComboBox->addItem("UDP Server", i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPSERVER); + + int h=19*60; + gridLayoutWidget_2->setGeometry(QRect(0, 0, 561, h)); + serverTunnelNameGroupBox->setGeometry(QRect(0, 0, 561, h)); + + { + const QString& type = tunnelConfig->getType(); + int index=0; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_SERVER)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTP)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_IRC)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPSERVER)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + } + + setupTunnelPane(tunnelConfig, + serverTunnelNameGroupBox, + gridLayoutWidget_2, tunnelTypeComboBox, + tunnelsFormGridLayoutWidget, tunnelsRow, height, h); + //this->tunnelGroupBox->setGeometry(QRect(0, tunnelsFormGridLayoutWidget->height()+10, 561, 18*40+10)); + + //host + ui.horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.hostLabel = new QLabel(gridLayoutWidget_2); + hostLabel->setObjectName(QStringLiteral("hostLabel")); + horizontalLayout_2->addWidget(hostLabel); + ui.hostLineEdit = new QLineEdit(gridLayoutWidget_2); + hostLineEdit->setObjectName(QStringLiteral("hostLineEdit")); + hostLineEdit->setText(tunnelConfig->gethost().c_str()); + QObject::connect(hostLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(hostLineEdit); + ui.hostHorizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(hostHorizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + + int gridIndex = 2; + { + int port = tunnelConfig->getport(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.portLabel = new QLabel(gridLayoutWidget_2); + portLabel->setObjectName(QStringLiteral("portLabel")); + horizontalLayout_2->addWidget(portLabel); + ui.portLineEdit = new QLineEdit(gridLayoutWidget_2); + portLineEdit->setObjectName(QStringLiteral("portLineEdit")); + portLineEdit->setText(QString::number(port)); + portLineEdit->setMaximumWidth(80); + QObject::connect(portLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(portLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string keys = tunnelConfig->getkeys(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.keysLabel = new QLabel(gridLayoutWidget_2); + keysLabel->setObjectName(QStringLiteral("keysLabel")); + horizontalLayout_2->addWidget(keysLabel); + ui.keysLineEdit = new QLineEdit(gridLayoutWidget_2); + keysLineEdit->setObjectName(QStringLiteral("keysLineEdit")); + keysLineEdit->setText(keys.c_str()); + QObject::connect(keysLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(keysLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + int inPort = tunnelConfig->getinPort(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.inPortLabel = new QLabel(gridLayoutWidget_2); + inPortLabel->setObjectName(QStringLiteral("inPortLabel")); + horizontalLayout_2->addWidget(inPortLabel); + ui.inPortLineEdit = new QLineEdit(gridLayoutWidget_2); + inPortLineEdit->setObjectName(QStringLiteral("inPortLineEdit")); + inPortLineEdit->setText(QString::number(inPort)); + inPortLineEdit->setMaximumWidth(80); + QObject::connect(inPortLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(inPortLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string accessList = tunnelConfig->getaccessList(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.accessListLabel = new QLabel(gridLayoutWidget_2); + accessListLabel->setObjectName(QStringLiteral("accessListLabel")); + horizontalLayout_2->addWidget(accessListLabel); + ui.accessListLineEdit = new QLineEdit(gridLayoutWidget_2); + accessListLineEdit->setObjectName(QStringLiteral("accessListLineEdit")); + accessListLineEdit->setText(accessList.c_str()); + QObject::connect(accessListLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(accessListLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string hostOverride = tunnelConfig->gethostOverride(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.hostOverrideLabel = new QLabel(gridLayoutWidget_2); + hostOverrideLabel->setObjectName(QStringLiteral("hostOverrideLabel")); + horizontalLayout_2->addWidget(hostOverrideLabel); + ui.hostOverrideLineEdit = new QLineEdit(gridLayoutWidget_2); + hostOverrideLineEdit->setObjectName(QStringLiteral("hostOverrideLineEdit")); + hostOverrideLineEdit->setText(hostOverride.c_str()); + QObject::connect(hostOverrideLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(hostOverrideLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string webIRCPass = tunnelConfig->getwebircpass(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.webIRCPassLabel = new QLabel(gridLayoutWidget_2); + webIRCPassLabel->setObjectName(QStringLiteral("webIRCPassLabel")); + horizontalLayout_2->addWidget(webIRCPassLabel); + ui.webIRCPassLineEdit = new QLineEdit(gridLayoutWidget_2); + webIRCPassLineEdit->setObjectName(QStringLiteral("webIRCPassLineEdit")); + webIRCPassLineEdit->setText(webIRCPass.c_str()); + QObject::connect(webIRCPassLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(webIRCPassLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + bool gzip = tunnelConfig->getgzip(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.gzipCheckBox = new QCheckBox(gridLayoutWidget_2); + gzipCheckBox->setObjectName(QStringLiteral("gzipCheckBox")); + gzipCheckBox->setChecked(gzip); + QObject::connect(gzipCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(gzipCheckBox); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + i2p::data::SigningKeyType sigType = tunnelConfig->getsigType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.sigTypeLabel = new QLabel(gridLayoutWidget_2); + sigTypeLabel->setObjectName(QStringLiteral("sigTypeLabel")); + horizontalLayout_2->addWidget(sigTypeLabel); + ui.sigTypeComboBox = SignatureTypeComboBoxFactory::createSignatureTypeComboBox(gridLayoutWidget_2, sigType); + sigTypeComboBox->setObjectName(QStringLiteral("sigTypeComboBox")); + QObject::connect(sigTypeComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(sigTypeComboBox); + QPushButton * lockButton2 = new QPushButton(gridLayoutWidget_2); + horizontalLayout_2->addWidget(lockButton2); + widgetlocks.add(new widgetlock(sigTypeComboBox, lockButton2)); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string address = tunnelConfig->getaddress(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.addressLabel = new QLabel(gridLayoutWidget_2); + addressLabel->setObjectName(QStringLiteral("addressLabel")); + horizontalLayout_2->addWidget(addressLabel); + ui.addressLineEdit = new QLineEdit(gridLayoutWidget_2); + addressLineEdit->setObjectName(QStringLiteral("addressLineEdit")); + addressLineEdit->setText(address.c_str()); + QObject::connect(addressLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(addressLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + bool isUniqueLocal = tunnelConfig->getisUniqueLocal(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.isUniqueLocalCheckBox = new QCheckBox(gridLayoutWidget_2); + isUniqueLocalCheckBox->setObjectName(QStringLiteral("isUniqueLocalCheckBox")); + isUniqueLocalCheckBox->setChecked(isUniqueLocal); + QObject::connect(gzipCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(isUniqueLocalCheckBox); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + int cryptoType = tunnelConfig->getcryptoType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + ui.cryptoTypeLabel = new QLabel(gridLayoutWidget_2); + cryptoTypeLabel->setObjectName(QStringLiteral("cryptoTypeLabel")); + horizontalLayout_2->addWidget(cryptoTypeLabel); + ui.cryptoTypeLineEdit = new QLineEdit(gridLayoutWidget_2); + cryptoTypeLineEdit->setObjectName(QStringLiteral("cryptoTypeLineEdit")); + cryptoTypeLineEdit->setText(QString::number(cryptoType)); + cryptoTypeLineEdit->setMaximumWidth(80); + QObject::connect(cryptoTypeLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(cryptoTypeLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + I2CPParameters& i2cpParameters = tunnelConfig->getI2cpParameters(); + appendControlsForI2CPParameters(i2cpParameters, gridIndex); + } + + retranslateServerTunnelForm(ui); + + tunnelGridLayout->invalidate(); + + return h; +} + +void ServerTunnelPane::deleteServerTunnelForm() { + TunnelPane::deleteTunnelForm(); + delete serverTunnelNameGroupBox;//->deleteLater(); + serverTunnelNameGroupBox=nullptr; + + //gridLayoutWidget_2->deleteLater(); + //gridLayoutWidget_2=nullptr; +} + + +ServerTunnelPane* ServerTunnelPane::asServerTunnelPane(){return this;} +ClientTunnelPane* ServerTunnelPane::asClientTunnelPane(){return nullptr;} diff --git a/src/ServerTunnelPane.h b/src/ServerTunnelPane.h new file mode 100644 index 0000000..de84424 --- /dev/null +++ b/src/ServerTunnelPane.h @@ -0,0 +1,183 @@ +#ifndef SERVERTUNNELPANE_H +#define SERVERTUNNELPANE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QVBoxLayout" +#include "QCheckBox" + +#include "assert.h" + +#include "TunnelPane.h" +#include "TunnelsPageUpdateListener.h" + +class ServerTunnelConfig; + +class ClientTunnelPane; + +class ServerTunnelPane : public TunnelPane { + Q_OBJECT + +public: + ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow); + virtual ~ServerTunnelPane(){} + + virtual ServerTunnelPane* asServerTunnelPane(); + virtual ClientTunnelPane* asClientTunnelPane(); + + int appendServerTunnelForm(ServerTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, + int tunnelsRow, int height); + void deleteServerTunnelForm(); + +private: + QGroupBox *serverTunnelNameGroupBox; + + //tunnel + QWidget *gridLayoutWidget_2; + + //host + QHBoxLayout *horizontalLayout_2; + QLabel *hostLabel; + QLineEdit *hostLineEdit; + QSpacerItem *hostHorizontalSpacer; + + //port + QLabel * portLabel; + QLineEdit * portLineEdit; + + //keys + QLabel * keysLabel; + QLineEdit * keysLineEdit; + + //inPort + QLabel * inPortLabel; + QLineEdit * inPortLineEdit; + + //cryptoType + QLabel * cryptoTypeLabel; + QLineEdit * cryptoTypeLineEdit; + + //accessList + QLabel * accessListLabel; + QLineEdit * accessListLineEdit; + + //hostOverride + QLabel * hostOverrideLabel; + QLineEdit * hostOverrideLineEdit; + + //webIRCPass + QLabel * webIRCPassLabel; + QLineEdit * webIRCPassLineEdit; + + //address + QLabel * addressLabel; + QLineEdit * addressLineEdit; + + //gzip + QCheckBox * gzipCheckBox; + + //isUniqueLocal + QCheckBox * isUniqueLocalCheckBox; + + //sigType + QLabel * sigTypeLabel; + QComboBox * sigTypeComboBox; + +protected slots: + virtual void setGroupBoxTitle(const QString & title); + +private: + void retranslateServerTunnelForm(ServerTunnelPane& /*ui*/) { + typeLabel->setText(QApplication::translate("srvTunForm", "Server tunnel type:", 0)); + hostLabel->setText(QApplication::translate("srvTunForm", "Host:", 0)); + portLabel->setText(QApplication::translate("srvTunForm", "Port:", 0)); + keysLabel->setText(QApplication::translate("srvTunForm", "Keys:", 0)); + inPortLabel->setText(QApplication::translate("srvTunForm", "InPort:", 0)); + cryptoTypeLabel->setText(QApplication::translate("srvTunForm", "Crypto type:", 0)); + accessListLabel->setText(QApplication::translate("srvTunForm", "Access list:", 0)); + hostOverrideLabel->setText(QApplication::translate("srvTunForm", "Host override:", 0)); + webIRCPassLabel->setText(QApplication::translate("srvTunForm", "WebIRC password:", 0)); + addressLabel->setText(QApplication::translate("srvTunForm", "Address:", 0)); + + gzipCheckBox->setText(QApplication::translate("srvTunForm", "GZip", 0)); + isUniqueLocalCheckBox->setText(QApplication::translate("srvTunForm", "Is unique local", 0)); + + sigTypeLabel->setText(QApplication::translate("cltTunForm", "Signature type:", 0)); + } + +protected: + virtual bool applyDataFromUIToTunnelConfig() { + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); + bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); + if(!ok)return false; + ServerTunnelConfig* stc=tunnelConfig->asServerTunnelConfig(); + assert(stc!=nullptr); + + if(!isValidSingleLine(hostLineEdit))return false; + if(!isValidSingleLine(portLineEdit))return false; + if(!isValidSingleLine(cryptoTypeLineEdit))return false; + if(!isValidSingleLine(keysLineEdit))return false; + if(!isValidSingleLine(inPortLineEdit))return false; + if(!isValidSingleLine(accessListLineEdit))return false; + if(!isValidSingleLine(hostOverrideLineEdit))return false; + if(!isValidSingleLine(webIRCPassLineEdit))return false; + if(!isValidSingleLine(addressLineEdit))return false; + + stc->sethost(hostLineEdit->text().toStdString()); + + auto portStr=portLineEdit->text(); + int portInt=portStr.toInt(&ok); + if(!ok){ + highlightWrongInput(QApplication::tr("Bad port, must be int.")+" "+cannotSaveSettings,portLineEdit); + return false; + } + stc->setport(portInt); + + auto cryptoTypeStr=cryptoTypeLineEdit->text(); + int cryptoTypeInt=cryptoTypeStr.toInt(&ok); + if(!ok){ + highlightWrongInput(QApplication::tr("Bad crypto type, must be int.")+" "+cannotSaveSettings,cryptoTypeLineEdit); + return false; + } + stc->setcryptoType(cryptoTypeInt); + + stc->setkeys(keysLineEdit->text().toStdString()); + + auto str=inPortLineEdit->text(); + int inPortInt=str.toInt(&ok); + if(!ok){ + highlightWrongInput(QApplication::tr("Bad inPort, must be int.")+" "+cannotSaveSettings,inPortLineEdit); + return false; + } + stc->setinPort(inPortInt); + + stc->setaccessList(accessListLineEdit->text().toStdString()); + + stc->sethostOverride(hostOverrideLineEdit->text().toStdString()); + + stc->setwebircpass(webIRCPassLineEdit->text().toStdString()); + + stc->setaddress(addressLineEdit->text().toStdString()); + + stc->setgzip(gzipCheckBox->isChecked()); + + stc->setisUniqueLocal(isUniqueLocalCheckBox->isChecked()); + + stc->setsigType(readSigTypeComboboxUI(sigTypeComboBox)); + return true; + } +}; + +#endif // SERVERTUNNELPANE_H diff --git a/src/SignatureTypeComboboxFactory.cpp b/src/SignatureTypeComboboxFactory.cpp new file mode 100644 index 0000000..9313741 --- /dev/null +++ b/src/SignatureTypeComboboxFactory.cpp @@ -0,0 +1,2 @@ +#include "SignatureTypeComboboxFactory.h" + diff --git a/src/SignatureTypeComboboxFactory.h b/src/SignatureTypeComboboxFactory.h new file mode 100644 index 0000000..f7cac65 --- /dev/null +++ b/src/SignatureTypeComboboxFactory.h @@ -0,0 +1,86 @@ +#ifndef SIGNATURETYPECOMBOBOXFACTORY_H +#define SIGNATURETYPECOMBOBOXFACTORY_H + +#include +#include +#include +#include "Identity.h" + +class SignatureTypeComboBoxFactory +{ + static const QVariant createUserData(const uint16_t sigType) { + return QVariant::fromValue((uint)sigType); + } + + static void addItem(QComboBox* signatureTypeCombobox, QString text, const uint16_t sigType) { + const QVariant userData = createUserData(sigType); + signatureTypeCombobox->addItem(text, userData); + } + +public: + static uint16_t getSigType(const QVariant& var) { + return (uint16_t)var.toInt(); + } + + static void fillComboBox(QComboBox* signatureTypeCombobox, uint16_t selectedSigType) { + /* + https://geti2p.net/spec/common-structures#certificate + все коды перечислены + это таблица "The defined Signing Public Key types are:" ? + да + + see also: Identity.h line 55 + */ + int index=0; + bool foundSelected=false; + + using namespace i2p::data; + + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "DSA_SHA1", 0), SIGNING_KEY_TYPE_DSA_SHA1); //0 + if(selectedSigType==SIGNING_KEY_TYPE_DSA_SHA1){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "ECDSA_SHA256_P256", 0), SIGNING_KEY_TYPE_ECDSA_SHA256_P256); //1 + if(selectedSigType==SIGNING_KEY_TYPE_ECDSA_SHA256_P256){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "ECDSA_SHA384_P384", 0), SIGNING_KEY_TYPE_ECDSA_SHA384_P384); //2 + if(selectedSigType==SIGNING_KEY_TYPE_ECDSA_SHA384_P384){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "ECDSA_SHA512_P521", 0), SIGNING_KEY_TYPE_ECDSA_SHA512_P521); //3 + if(selectedSigType==SIGNING_KEY_TYPE_ECDSA_SHA512_P521){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "RSA_SHA256_2048", 0), SIGNING_KEY_TYPE_RSA_SHA256_2048); //4 + if(selectedSigType==SIGNING_KEY_TYPE_RSA_SHA256_2048){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "RSA_SHA384_3072", 0), SIGNING_KEY_TYPE_RSA_SHA384_3072); //5 + if(selectedSigType==SIGNING_KEY_TYPE_RSA_SHA384_3072){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "RSA_SHA512_4096", 0), SIGNING_KEY_TYPE_RSA_SHA512_4096); //6 + if(selectedSigType==SIGNING_KEY_TYPE_RSA_SHA512_4096){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "EDDSA_SHA512_ED25519", 0), SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); //7 + if(selectedSigType==SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "EDDSA_SHA512_ED25519PH", 0), SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph); //8 + if(selectedSigType==SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + // the following signature type should never appear in netid=2 + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256", 0), SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256); //9 + if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_TC26_A_512_GOSTR3411_512", 0), SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512); //10 + if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + if(!foundSelected){ + addItem(signatureTypeCombobox, QString::number(selectedSigType), selectedSigType); //unknown sigtype + signatureTypeCombobox->setCurrentIndex(index); + } + } + + static QComboBox* createSignatureTypeComboBox(QWidget* parent, uint16_t selectedSigType) { + QComboBox* signatureTypeCombobox = new QComboBox(parent); + fillComboBox(signatureTypeCombobox, selectedSigType); + return signatureTypeCombobox; + } +}; + +#endif // SIGNATURETYPECOMBOBOXFACTORY_H diff --git a/src/TunnelConfig.cpp b/src/TunnelConfig.cpp new file mode 100644 index 0000000..a2cdf92 --- /dev/null +++ b/src/TunnelConfig.cpp @@ -0,0 +1,67 @@ +#include "TunnelConfig.h" + +void TunnelConfig::saveHeaderToStringStream(std::stringstream& out) { + out << "[" << name << "]\n" + << "type=" << type.toStdString() << "\n"; +} + +void TunnelConfig::saveI2CPParametersToStringStream(std::stringstream& out) { + if (i2cpParameters.getInbound_length().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNEL_LENGTH) + out << i2p::client::I2CP_PARAM_INBOUND_TUNNEL_LENGTH << "=" + << i2cpParameters.getInbound_length().toStdString() << "\n"; + if (i2cpParameters.getOutbound_length().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNEL_LENGTH) + out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH << "=" + << i2cpParameters.getOutbound_length().toStdString() << "\n"; + if (i2cpParameters.getInbound_quantity().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNELS_QUANTITY) + out << i2p::client::I2CP_PARAM_INBOUND_TUNNELS_QUANTITY << "=" + << i2cpParameters.getInbound_quantity().toStdString() << "\n"; + if (i2cpParameters.getOutbound_quantity().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNELS_QUANTITY) + out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY << "=" + << i2cpParameters.getOutbound_quantity().toStdString() << "\n"; + if (i2cpParameters.getCrypto_tagsToSend().toUShort() != i2p::client::DEFAULT_TAGS_TO_SEND) + out << i2p::client::I2CP_PARAM_TAGS_TO_SEND << "=" + << i2cpParameters.getCrypto_tagsToSend().toStdString() << "\n"; + if (!i2cpParameters.getExplicitPeers().isEmpty()) //todo #947 + out << i2p::client::I2CP_PARAM_EXPLICIT_PEERS << "=" + << i2cpParameters.getExplicitPeers().toStdString() << "\n"; + out << i2p::client::I2CP_PARAM_LEASESET_AUTH_TYPE << "=" + << i2cpParameters.get_i2cp_leaseSetAuthType().toStdString() << "\n"; + out << i2p::client::I2CP_PARAM_LEASESET_ENCRYPTION_TYPE << "=" + << i2cpParameters.get_i2cp_leaseSetEncType().toStdString() << "\n"; + out << i2p::client::I2CP_PARAM_LEASESET_PRIV_KEY << "=" + << i2cpParameters.get_i2cp_leaseSetPrivKey().toStdString() << "\n"; + out << i2p::client::I2CP_PARAM_LEASESET_TYPE << "=" + << i2cpParameters.get_i2cp_leaseSetType().toStdString() << "\n"; + out << i2p::client::I2CP_PARAM_STREAMING_ANSWER_PINGS << "=" + << (i2cpParameters.get_i2p_streaming_answerPings() ? "true" : "false") << "\n"; + out << i2p::client::I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY << "=" + << i2cpParameters.get_i2p_streaming_initialAckDelay().toStdString() << "\n"; + out << "\n"; +} + +void ClientTunnelConfig::saveToStringStream(std::stringstream& out) { + out << "address=" << address << "\n" + << "port=" << port << "\n" + << "destination=" << dest << "\n" + << "destinationport=" << destinationPort << "\n" + << "cryptoType=" << getcryptoType() << "\n" + << "signaturetype=" << sigType << "\n"; + if(!keys.empty()) out << "keys=" << keys << "\n"; +} + + +void ServerTunnelConfig::saveToStringStream(std::stringstream& out) { + out << "host=" << host << "\n" + << "port=" << port << "\n" + << "signaturetype=" << sigType << "\n" + << "inport=" << inPort << "\n"; + if(accessList.size()>0) { out << "accesslist=" << accessList << "\n"; } + out << "gzip=" << (gzip?"true":"false") << "\n" + << "cryptoType=" << getcryptoType() << "\n" + << "enableuniquelocal=" << (isUniqueLocal?"true":"false") << "\n" + << "address=" << address << "\n" + << "hostoverride=" << hostOverride << "\n" + << "webircpassword=" << webircpass << "\n"; + if(!keys.empty()) out << "keys=" << keys << "\n"; +} + diff --git a/src/TunnelConfig.h b/src/TunnelConfig.h new file mode 100644 index 0000000..b33f882 --- /dev/null +++ b/src/TunnelConfig.h @@ -0,0 +1,260 @@ +#ifndef TUNNELCONFIG_H +#define TUNNELCONFIG_H + +#include "QString" +#include + +#include "ClientContext.h" +#include "Destination.h" +#include "TunnelsPageUpdateListener.h" + + +class I2CPParameters{ + QString inbound_length;//number of hops of an inbound tunnel. 3 by default; lower value is faster but dangerous + QString outbound_length;//number of hops of an outbound tunnel. 3 by default; lower value is faster but dangerous + QString inbound_quantity; //number of inbound tunnels. 5 by default + QString outbound_quantity; //number of outbound tunnels. 5 by default + QString crypto_tagsToSend; //number of ElGamal/AES tags to send. 40 by default; too low value may cause problems with tunnel building + QString explicitPeers; //list of comma-separated b64 addresses of peers to use, default: unset + QString i2p_streaming_initialAckDelay; //i2p.streaming.initialAckDelay -- milliseconds to wait before sending Ack. 200 by default + bool i2p_streaming_answerPings; //i2p.streaming.answerPings -- enable sending pongs. true by default + QString i2cp_leaseSetType; //i2cp.leaseSetType -- type of LeaseSet to be sent. 1, 3 or 5. 1 by default + QString i2cp_leaseSetEncType; //i2cp.leaseSetEncType -- comma separated encryption types to be used in LeaseSet type 3 or 5. Identity's type by default + QString i2cp_leaseSetPrivKey; //i2cp.leaseSetPrivKey -- decryption key for encrypted LeaseSet in base64. PSK or private DH + QString i2cp_leaseSetAuthType; //i2cp.leaseSetAuthType -- authentication type for encrypted LeaseSet. 0 - no authentication(default), 1 - DH, 2 - PSK +public: + I2CPParameters(): inbound_length(), + outbound_length(), + inbound_quantity(), + outbound_quantity(), + crypto_tagsToSend(), + explicitPeers(), + i2p_streaming_initialAckDelay(), + i2p_streaming_answerPings(true), + i2cp_leaseSetType(), + i2cp_leaseSetEncType(), + i2cp_leaseSetPrivKey(), + i2cp_leaseSetAuthType() {} + const QString& getInbound_length(){return inbound_length;} + const QString& getOutbound_length(){return outbound_length;} + const QString& getInbound_quantity(){return inbound_quantity;} + const QString& getOutbound_quantity(){return outbound_quantity;} + const QString& getCrypto_tagsToSend(){return crypto_tagsToSend;} + const QString& getExplicitPeers(){return explicitPeers;} + const QString& get_i2p_streaming_initialAckDelay(){return i2p_streaming_initialAckDelay;} + bool get_i2p_streaming_answerPings(){return i2p_streaming_answerPings;} + const QString& get_i2cp_leaseSetType(){return i2cp_leaseSetType;} + const QString& get_i2cp_leaseSetEncType(){return i2cp_leaseSetEncType;} + const QString& get_i2cp_leaseSetPrivKey(){return i2cp_leaseSetPrivKey;} + const QString& get_i2cp_leaseSetAuthType(){return i2cp_leaseSetAuthType;} + void setInbound_length(QString inbound_length_){inbound_length=inbound_length_;} + void setOutbound_length(QString outbound_length_){outbound_length=outbound_length_;} + void setInbound_quantity(QString inbound_quantity_){inbound_quantity=inbound_quantity_;} + void setOutbound_quantity(QString outbound_quantity_){outbound_quantity=outbound_quantity_;} + void setCrypto_tagsToSend(QString crypto_tagsToSend_){crypto_tagsToSend=crypto_tagsToSend_;} + void setExplicitPeers(QString explicitPeers_){explicitPeers=explicitPeers_;} + void set_i2p_streaming_initialAckDelay(QString i2p_streaming_initialAckDelay_){i2p_streaming_initialAckDelay=i2p_streaming_initialAckDelay_;} + void set_i2p_streaming_answerPings(bool i2p_streaming_answerPings_){i2p_streaming_answerPings=i2p_streaming_answerPings_;} + void set_i2cp_leaseSetType(QString i2cp_leaseSetType_){i2cp_leaseSetType=i2cp_leaseSetType_;} + void set_i2cp_leaseSetEncType(QString i2cp_leaseSetEncType_){i2cp_leaseSetEncType=i2cp_leaseSetEncType_;} + void set_i2cp_leaseSetPrivKey(QString i2cp_leaseSetPrivKey_){i2cp_leaseSetPrivKey=i2cp_leaseSetPrivKey_;} + void set_i2cp_leaseSetAuthType(QString i2cp_leaseSetAuthType_){i2cp_leaseSetAuthType=i2cp_leaseSetAuthType_;} +}; + + +class ClientTunnelConfig; +class ServerTunnelConfig; + +class TunnelPane; + +class TunnelConfig { + /* + const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client"; + const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server"; + const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http"; + const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc"; + const char I2P_TUNNELS_SECTION_TYPE_UDPCLIENT[] = "udpclient"; + const char I2P_TUNNELS_SECTION_TYPE_UDPSERVER[] = "udpserver"; + const char I2P_TUNNELS_SECTION_TYPE_SOCKS[] = "socks"; + const char I2P_TUNNELS_SECTION_TYPE_WEBSOCKS[] = "websocks"; + const char I2P_TUNNELS_SECTION_TYPE_HTTPPROXY[] = "httpproxy"; + */ + QString type; + std::string name; + TunnelPane* tunnelPane; + int cryptoType; +public: + TunnelConfig(std::string name_, QString& type_, I2CPParameters& i2cpParameters_, int cryptoType_): + type(type_), name(name_), cryptoType(cryptoType_), i2cpParameters(i2cpParameters_) {} + virtual ~TunnelConfig(){} + const QString& getType(){return type;} + const std::string& getName(){return name;} + int getcryptoType(){return cryptoType;} + void setType(const QString& type_){type=type_;} + void setName(const std::string& name_){name=name_;} + I2CPParameters& getI2cpParameters(){return i2cpParameters;} + void saveHeaderToStringStream(std::stringstream& out); + void saveI2CPParametersToStringStream(std::stringstream& out); + virtual void saveToStringStream(std::stringstream& out)=0; + virtual ClientTunnelConfig* asClientTunnelConfig()=0; + virtual ServerTunnelConfig* asServerTunnelConfig()=0; + void setTunnelPane(TunnelPane* tp){this->tunnelPane = tp;} + TunnelPane* getTunnelPane() {return tunnelPane;} + void setcryptoType(int cryptoType_){cryptoType=cryptoType_;} +private: + I2CPParameters i2cpParameters; +}; + +/* +# mandatory parameters: + std::string dest; + if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) + dest = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION); + int port = section.second.get (I2P_CLIENT_TUNNEL_PORT); +# optional parameters (may be omitted) + std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, ""); + std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); + int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); + i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); +# * keys -- our identity, if unset, will be generated on every startup, +# if set and file missing, keys will be generated and placed to this file +# * address -- local interface to bind +# * signaturetype -- signature type for new destination. 0 (DSA/SHA1), 1 (EcDSA/SHA256) or 7 (EdDSA/SHA512) +[somelabel] +type = client +address = 127.0.0.1 +port = 6668 +destination = irc.postman.i2p +keys = irc-keys.dat +*/ +class ClientTunnelConfig : public TunnelConfig { + std::string dest; + int port; + std::string keys; + std::string address; + int destinationPort; + i2p::data::SigningKeyType sigType; +public: + ClientTunnelConfig(std::string name_, QString type_, I2CPParameters& i2cpParameters_, + std::string dest_, + int port_, + std::string keys_, + std::string address_, + int destinationPort_, + i2p::data::SigningKeyType sigType_, + int cryptoType_): TunnelConfig(name_, type_, i2cpParameters_, cryptoType_), + dest(dest_), + port(port_), + keys(keys_), + address(address_), + destinationPort(destinationPort_), + sigType(sigType_) {} + std::string& getdest(){return dest;} + int getport(){return port;} + std::string & getkeys(){return keys;} + std::string & getaddress(){return address;} + int getdestinationPort(){return destinationPort;} + i2p::data::SigningKeyType getsigType(){return sigType;} + void setdest(const std::string& dest_){dest=dest_;} + void setport(int port_){port=port_;} + void setkeys(const std::string & keys_){keys=keys_;} + void setaddress(const std::string & address_){address=address_;} + void setdestinationPort(int destinationPort_){destinationPort=destinationPort_;} + void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;} + virtual void saveToStringStream(std::stringstream& out); + virtual ClientTunnelConfig* asClientTunnelConfig(){return this;} + virtual ServerTunnelConfig* asServerTunnelConfig(){return nullptr;} +}; + +/* +# mandatory parameters: +# * host -- ip address of our service +# * port -- port of our service +# * keys -- file with LeaseSet of address in i2p + std::string host = section.second.get (I2P_SERVER_TUNNEL_HOST); + int port = section.second.get (I2P_SERVER_TUNNEL_PORT); + std::string keys = section.second.get (I2P_SERVER_TUNNEL_KEYS); +# optional parameters (may be omitted) + int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0); + std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, ""); + std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, ""); + std::string webircpass = section.second.get (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); + bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); + i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); + bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); +# * inport -- optional, i2p service port, if unset - the same as 'port' +# * accesslist -- comma-separated list of i2p addresses, allowed to connect +# every address is b32 without '.b32.i2p' part +[somelabel] +type = server +host = 127.0.0.1 +port = 6667 +keys = irc.dat +*/ +class ServerTunnelConfig : public TunnelConfig { + std::string host; + int port; + std::string keys; + int inPort; + std::string accessList; + std::string hostOverride; + std::string webircpass; + bool gzip; + i2p::data::SigningKeyType sigType; + std::string address; + bool isUniqueLocal; +public: + ServerTunnelConfig(std::string name_, QString type_, I2CPParameters& i2cpParameters_, + std::string host_, + int port_, + std::string keys_, + int inPort_, + std::string accessList_, + std::string hostOverride_, + std::string webircpass_, + bool gzip_, + i2p::data::SigningKeyType sigType_, + std::string address_, + bool isUniqueLocal_, + int cryptoType_): TunnelConfig(name_, type_, i2cpParameters_, cryptoType_), + host(host_), + port(port_), + keys(keys_), + inPort(inPort_), + accessList(accessList_), + hostOverride(hostOverride_), + webircpass(webircpass_), + gzip(gzip_), + sigType(sigType_), + address(address_), + isUniqueLocal(isUniqueLocal_) {} + std::string& gethost(){return host;} + int getport(){return port;} + std::string& getkeys(){return keys;} + int getinPort(){return inPort;} + std::string& getaccessList(){return accessList;} + std::string& gethostOverride(){return hostOverride;} + std::string& getwebircpass(){return webircpass;} + bool getgzip(){return gzip;} + i2p::data::SigningKeyType getsigType(){return sigType;} + std::string& getaddress(){return address;} + bool getisUniqueLocal(){return isUniqueLocal;} + void sethost(const std::string& host_){host=host_;} + void setport(int port_){port=port_;} + void setkeys(const std::string& keys_){keys=keys_;} + void setinPort(int inPort_){inPort=inPort_;} + void setaccessList(const std::string& accessList_){accessList=accessList_;} + void sethostOverride(const std::string& hostOverride_){hostOverride=hostOverride_;} + void setwebircpass(const std::string& webircpass_){webircpass=webircpass_;} + void setgzip(bool gzip_){gzip=gzip_;} + void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;} + void setaddress(const std::string& address_){address=address_;} + void setisUniqueLocal(bool isUniqueLocal_){isUniqueLocal=isUniqueLocal_;} + virtual void saveToStringStream(std::stringstream& out); + virtual ClientTunnelConfig* asClientTunnelConfig(){return nullptr;} + virtual ServerTunnelConfig* asServerTunnelConfig(){return this;} +}; + + +#endif // TUNNELCONFIG_H diff --git a/src/TunnelPane.cpp b/src/TunnelPane.cpp new file mode 100644 index 0000000..7e15a6a --- /dev/null +++ b/src/TunnelPane.cpp @@ -0,0 +1,405 @@ +#include "TunnelPane.h" + +#include "QMessageBox" +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "I2pdQtUtil.h" + +TunnelPane::TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunnelConfig_, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow_): + QObject(), + mainWindow(mainWindow_), + wrongInputPane(wrongInputPane_), + wrongInputLabel(wrongInputLabel_), + tunnelConfig(tunnelConfig_), + tunnelsPageUpdateListener(tunnelsPageUpdateListener_), + gridLayoutWidget_2(nullptr) {} + +void TunnelPane::setupTunnelPane( + TunnelConfig* tunnelConfig, + QGroupBox *tunnelGroupBox, + QWidget* gridLayoutWidget_2, QComboBox * tunnelTypeComboBox, + QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height, int h) { + tunnelGroupBox->setGeometry(0, tunnelsFormGridLayoutWidget->height(), gridLayoutWidget_2->width(), h); + tunnelsFormGridLayoutWidget->resize(527, tunnelsFormGridLayoutWidget->height()+h); + + QObject::connect(tunnelTypeComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(updated())); + + + this->tunnelGroupBox=tunnelGroupBox; + + gridLayoutWidget_2->setObjectName(QStringLiteral("gridLayoutWidget_2")); + this->gridLayoutWidget_2=gridLayoutWidget_2; + tunnelGridLayout = new QVBoxLayout(gridLayoutWidget_2); + tunnelGridLayout->setObjectName(QStringLiteral("tunnelGridLayout")); + tunnelGridLayout->setContentsMargins(10, 25, 10, 10); + tunnelGridLayout->setSpacing(5); + + //header + QHBoxLayout *headerHorizontalLayout = new QHBoxLayout(); + headerHorizontalLayout->setObjectName(QStringLiteral("headerHorizontalLayout")); + + nameLabel = new QLabel(gridLayoutWidget_2); + nameLabel->setObjectName(QStringLiteral("nameLabel")); + headerHorizontalLayout->addWidget(nameLabel); + nameLineEdit = new QLineEdit(gridLayoutWidget_2); + nameLineEdit->setObjectName(QStringLiteral("nameLineEdit")); + const QString& tunnelName=tunnelConfig->getName().c_str(); + nameLineEdit->setText(tunnelName); + setGroupBoxTitle(tunnelName); + + QObject::connect(nameLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + + headerHorizontalLayout->addWidget(nameLineEdit); + headerHorizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + headerHorizontalLayout->addItem(headerHorizontalSpacer); + deletePushButton = new QPushButton(gridLayoutWidget_2); + deletePushButton->setObjectName(QStringLiteral("deletePushButton")); + QObject::connect(deletePushButton, SIGNAL(released()), + this, SLOT(deleteButtonReleased()));//MainWindow::DeleteTunnelNamed(std::string name) { + headerHorizontalLayout->addWidget(deletePushButton); + tunnelGridLayout->addLayout(headerHorizontalLayout); + + //type + { + //const QString& type = tunnelConfig->getType(); + QHBoxLayout * horizontalLayout_ = new QHBoxLayout(); + horizontalLayout_->setObjectName(QStringLiteral("horizontalLayout_")); + typeLabel = new QLabel(gridLayoutWidget_2); + typeLabel->setObjectName(QStringLiteral("typeLabel")); + horizontalLayout_->addWidget(typeLabel); + horizontalLayout_->addWidget(tunnelTypeComboBox); + QPushButton * lockButton1 = new QPushButton(gridLayoutWidget_2); + horizontalLayout_->addWidget(lockButton1); + widgetlocks.add(new widgetlock(tunnelTypeComboBox, lockButton1)); + this->tunnelTypeComboBox=tunnelTypeComboBox; + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_); + } + + retranslateTunnelForm(*this); +} + +void TunnelPane::deleteWidget() { + //gridLayoutWidget_2->deleteLater(); + tunnelGroupBox->deleteLater(); +} + +void TunnelPane::appendControlsForI2CPParameters(I2CPParameters& i2cpParameters, int& gridIndex) { + { + //number of hops of an inbound tunnel + const QString& inbound_length=i2cpParameters.getInbound_length(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + inbound_lengthLabel = new QLabel(gridLayoutWidget_2); + inbound_lengthLabel->setObjectName(QStringLiteral("inbound_lengthLabel")); + horizontalLayout_2->addWidget(inbound_lengthLabel); + inbound_lengthLineEdit = new QLineEdit(gridLayoutWidget_2); + inbound_lengthLineEdit->setObjectName(QStringLiteral("inbound_lengthLineEdit")); + inbound_lengthLineEdit->setText(inbound_length); + inbound_lengthLineEdit->setMaximumWidth(80); + QObject::connect(inbound_lengthLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(inbound_lengthLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of hops of an outbound tunnel + const QString& outbound_length=i2cpParameters.getOutbound_length(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + outbound_lengthLabel = new QLabel(gridLayoutWidget_2); + outbound_lengthLabel->setObjectName(QStringLiteral("outbound_lengthLabel")); + horizontalLayout_2->addWidget(outbound_lengthLabel); + outbound_lengthLineEdit = new QLineEdit(gridLayoutWidget_2); + outbound_lengthLineEdit->setObjectName(QStringLiteral("outbound_lengthLineEdit")); + outbound_lengthLineEdit->setText(outbound_length); + outbound_lengthLineEdit->setMaximumWidth(80); + QObject::connect(outbound_lengthLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(outbound_lengthLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of inbound tunnels + const QString& inbound_quantity=i2cpParameters.getInbound_quantity(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + inbound_quantityLabel = new QLabel(gridLayoutWidget_2); + inbound_quantityLabel->setObjectName(QStringLiteral("inbound_quantityLabel")); + horizontalLayout_2->addWidget(inbound_quantityLabel); + inbound_quantityLineEdit = new QLineEdit(gridLayoutWidget_2); + inbound_quantityLineEdit->setObjectName(QStringLiteral("inbound_quantityLineEdit")); + inbound_quantityLineEdit->setText(inbound_quantity); + inbound_quantityLineEdit->setMaximumWidth(80); + QObject::connect(inbound_quantityLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(inbound_quantityLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of outbound tunnels + const QString& outbound_quantity=i2cpParameters.getOutbound_quantity(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + outbound_quantityLabel = new QLabel(gridLayoutWidget_2); + outbound_quantityLabel->setObjectName(QStringLiteral("outbound_quantityLabel")); + horizontalLayout_2->addWidget(outbound_quantityLabel); + outbound_quantityLineEdit = new QLineEdit(gridLayoutWidget_2); + outbound_quantityLineEdit->setObjectName(QStringLiteral("outbound_quantityLineEdit")); + outbound_quantityLineEdit->setText(outbound_quantity); + outbound_quantityLineEdit->setMaximumWidth(80); + QObject::connect(outbound_quantityLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(outbound_quantityLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of ElGamal/AES tags to send + const QString& crypto_tagsToSend=i2cpParameters.getCrypto_tagsToSend(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + crypto_tagsToSendLabel = new QLabel(gridLayoutWidget_2); + crypto_tagsToSendLabel->setObjectName(QStringLiteral("crypto_tagsToSendLabel")); + horizontalLayout_2->addWidget(crypto_tagsToSendLabel); + crypto_tagsToSendLineEdit = new QLineEdit(gridLayoutWidget_2); + crypto_tagsToSendLineEdit->setObjectName(QStringLiteral("crypto_tagsToSendLineEdit")); + crypto_tagsToSendLineEdit->setText(crypto_tagsToSend); + crypto_tagsToSendLineEdit->setMaximumWidth(80); + QObject::connect(crypto_tagsToSendLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(crypto_tagsToSendLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + { + //explicitPeers -- list of comma-separated b64 addresses of peers to use, default: unset + const QString& value=i2cpParameters.getExplicitPeers(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + QLabel *_Label; + explicitPeersLabel = _Label = new QLabel(gridLayoutWidget_2); + _Label->setObjectName(QStringLiteral("_Label")); + horizontalLayout_2->addWidget(_Label); + QLineEdit *_LineEdit; + explicitPeersLineEdit = _LineEdit = new QLineEdit(gridLayoutWidget_2); + _LineEdit->setObjectName(QStringLiteral("_LineEdit")); + _LineEdit->setText(value); + _LineEdit->setMaximumWidth(80); + QObject::connect(_LineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(_LineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + { + //i2p.streaming.initialAckDelay -- milliseconds to wait before sending Ack. 200 by default + const QString& value=i2cpParameters.get_i2p_streaming_initialAckDelay(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + QLabel *_Label; + i2p_streaming_initialAckDelayLabel = _Label = new QLabel(gridLayoutWidget_2); + _Label->setObjectName(QStringLiteral("_Label")); + horizontalLayout_2->addWidget(_Label); + QLineEdit *_LineEdit; + i2p_streaming_initialAckDelayLineEdit = _LineEdit = new QLineEdit(gridLayoutWidget_2); + _LineEdit->setObjectName(QStringLiteral("_LineEdit")); + _LineEdit->setText(value); + _LineEdit->setMaximumWidth(80); + QObject::connect(_LineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(_LineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + { + //i2p.streaming.answerPings -- enable sending pongs. true by default + const bool value=i2cpParameters.get_i2p_streaming_answerPings(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + QCheckBox *_CheckBox; + i2p_streaming_answerPingsCheckBox = _CheckBox = new QCheckBox(gridLayoutWidget_2); + _CheckBox->setObjectName(QStringLiteral("_CheckBox")); + horizontalLayout_2->addWidget(_CheckBox); + _CheckBox->setChecked(value); + QObject::connect(_CheckBox, SIGNAL(toggled(bool)), + this, SLOT(updated())); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + { + //i2cp.leaseSetType -- type of LeaseSet to be sent. 1, 3 or 5. 1 by default + const QString& value=i2cpParameters.get_i2cp_leaseSetType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + QLabel *_Label; + i2cp_leaseSetTypeLabel = _Label = new QLabel(gridLayoutWidget_2); + _Label->setObjectName(QStringLiteral("_Label")); + horizontalLayout_2->addWidget(_Label); + QLineEdit *_LineEdit; + i2cp_leaseSetTypeLineEdit = _LineEdit = new QLineEdit(gridLayoutWidget_2); + _LineEdit->setObjectName(QStringLiteral("_LineEdit")); + _LineEdit->setText(value); + _LineEdit->setMaximumWidth(80); + QObject::connect(_LineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(_LineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + { + //i2cp.leaseSetEncType -- comma separated encryption types to be used in LeaseSet type 3 or 5. Identity's type by default + const QString& value=i2cpParameters.get_i2cp_leaseSetEncType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + QLabel *_Label; + i2cp_leaseSetEncTypeLabel = _Label = new QLabel(gridLayoutWidget_2); + _Label->setObjectName(QStringLiteral("_Label")); + horizontalLayout_2->addWidget(_Label); + QLineEdit *_LineEdit; + i2cp_leaseSetEncTypeLineEdit = _LineEdit = new QLineEdit(gridLayoutWidget_2); + _LineEdit->setObjectName(QStringLiteral("_LineEdit")); + _LineEdit->setText(value); + _LineEdit->setMaximumWidth(80); + QObject::connect(_LineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(_LineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + { + //i2cp.leaseSetPrivKey -- decryption key for encrypted LeaseSet in base64. PSK or private DH + const QString& value=i2cpParameters.get_i2cp_leaseSetPrivKey(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + QLabel *_Label; + i2cp_leaseSetPrivKeyLabel = _Label = new QLabel(gridLayoutWidget_2); + _Label->setObjectName(QStringLiteral("_Label")); + horizontalLayout_2->addWidget(_Label); + QLineEdit *_LineEdit; + i2cp_leaseSetPrivKeyLineEdit = _LineEdit = new QLineEdit(gridLayoutWidget_2); + _LineEdit->setObjectName(QStringLiteral("_LineEdit")); + _LineEdit->setText(value); + _LineEdit->setMaximumWidth(80); + QObject::connect(_LineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(_LineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + { + //i2cp.leaseSetAuthType -- authentication type for encrypted LeaseSet. 0 - no authentication(default), 1 - DH, 2 - PSK + const QString& value=i2cpParameters.get_i2cp_leaseSetAuthType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + QLabel *_Label; + i2cp_leaseSetAuthTypeLabel = _Label = new QLabel(gridLayoutWidget_2); + _Label->setObjectName(QStringLiteral("_Label")); + horizontalLayout_2->addWidget(_Label); + QLineEdit *_LineEdit; + i2cp_leaseSetAuthTypeLineEdit = _LineEdit = new QLineEdit(gridLayoutWidget_2); + _LineEdit->setObjectName(QStringLiteral("_LineEdit")); + _LineEdit->setText(value); + _LineEdit->setMaximumWidth(80); + QObject::connect(_LineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(_LineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + retranslateI2CPParameters(); +} + +void TunnelPane::updated() { + std::string oldName=tunnelConfig->getName(); + //validate and show red if invalid + hideWrongInputLabel(); + if(!mainWindow->applyTunnelsUiToConfigs())return; + tunnelsPageUpdateListener->updated(oldName, tunnelConfig); +} + +void TunnelPane::deleteButtonReleased() { + QMessageBox msgBox; + msgBox.setText(QApplication::tr("Are you sure to delete this tunnel?")); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Cancel); + int ret = msgBox.exec(); + switch (ret) { + case QMessageBox::Ok: + // OK was clicked + hideWrongInputLabel(); + tunnelsPageUpdateListener->needsDeleting(tunnelConfig->getName()); + break; + case QMessageBox::Cancel: + // Cancel was clicked + return; + } +} + +/* +const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client"; +const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server"; +const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http"; +const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc"; +const char I2P_TUNNELS_SECTION_TYPE_UDPCLIENT[] = "udpclient"; +const char I2P_TUNNELS_SECTION_TYPE_UDPSERVER[] = "udpserver"; +const char I2P_TUNNELS_SECTION_TYPE_SOCKS[] = "socks"; +const char I2P_TUNNELS_SECTION_TYPE_WEBSOCKS[] = "websocks"; +const char I2P_TUNNELS_SECTION_TYPE_HTTPPROXY[] = "httpproxy"; +*/ +QString TunnelPane::readTunnelTypeComboboxData() { + return tunnelTypeComboBox->currentData().toString(); +} + +i2p::data::SigningKeyType TunnelPane::readSigTypeComboboxUI(QComboBox* sigTypeComboBox) { + return (i2p::data::SigningKeyType) sigTypeComboBox->currentData().toInt(); +} + +void TunnelPane::deleteTunnelForm() { + widgetlocks.deleteListeners(); +} + +void TunnelPane::highlightWrongInput(QString warningText, QWidget* controlWithWrongInput) { + wrongInputPane->setVisible(true); + wrongInputLabel->setText(warningText); + mainWindow->adjustSizesAccordingToWrongLabel(); + if(controlWithWrongInput){ + mainWindow->ui->tunnelsScrollArea->ensureWidgetVisible(controlWithWrongInput); + controlWithWrongInput->setFocus(); + } + mainWindow->showTunnelsPage(); +} + +void TunnelPane::hideWrongInputLabel() const { + wrongInputPane->setVisible(false); + mainWindow->adjustSizesAccordingToWrongLabel(); +} + +bool TunnelPane::isValidSingleLine(QLineEdit* widget) { + return ::isValidSingleLine(widget, WrongInputPageEnum::tunnelsSettingsPage, mainWindow); +} diff --git a/src/TunnelPane.h b/src/TunnelPane.h new file mode 100644 index 0000000..ac21181 --- /dev/null +++ b/src/TunnelPane.h @@ -0,0 +1,191 @@ +#ifndef TUNNELPANE_H +#define TUNNELPANE_H + +#include "QObject" +#include "QWidget" +#include "QComboBox" +#include "QGridLayout" +#include "QLabel" +#include "QPushButton" +#include "QApplication" +#include "QLineEdit" +#include "QGroupBox" +#include "QVBoxLayout" +#include "QCheckBox" + +#include "TunnelConfig.h" + +#include +#include + +class ServerTunnelPane; +class ClientTunnelPane; + +class TunnelConfig; +class I2CPParameters; + +class MainWindow; + +class TunnelPane : public QObject { + + Q_OBJECT + +public: + TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow_); + virtual ~TunnelPane(){} + + void deleteTunnelForm(); + + void hideWrongInputLabel() const; + void highlightWrongInput(QString warningText, QWidget* controlWithWrongInput); + + virtual ServerTunnelPane* asServerTunnelPane()=0; + virtual ClientTunnelPane* asClientTunnelPane()=0; + + void deleteWidget(); + +protected: + MainWindow* mainWindow; + QWidget * wrongInputPane; + QLabel* wrongInputLabel; + TunnelConfig* tunnelConfig; + widgetlockregistry widgetlocks; + TunnelsPageUpdateListener* tunnelsPageUpdateListener; + QVBoxLayout *tunnelGridLayout; + QGroupBox *tunnelGroupBox; + QWidget* gridLayoutWidget_2; + + //header + QLabel *nameLabel; + QLineEdit *nameLineEdit; +public: + QLineEdit * getNameLineEdit() { return nameLineEdit; } + +public slots: + void updated(); + void deleteButtonReleased(); + +protected: + QSpacerItem *headerHorizontalSpacer; + QPushButton *deletePushButton; + + //type + QComboBox *tunnelTypeComboBox; + QLabel *typeLabel; + + //i2cp + + QLabel * inbound_lengthLabel; + QLineEdit * inbound_lengthLineEdit; + + QLabel * outbound_lengthLabel; + QLineEdit * outbound_lengthLineEdit; + + QLabel * inbound_quantityLabel; + QLineEdit * inbound_quantityLineEdit; + + QLabel * outbound_quantityLabel; + QLineEdit * outbound_quantityLineEdit; + + QLabel * crypto_tagsToSendLabel; + QLineEdit * crypto_tagsToSendLineEdit; + + QLabel * explicitPeersLabel; + QLineEdit * explicitPeersLineEdit; + + QLabel * i2p_streaming_initialAckDelayLabel; + QLineEdit * i2p_streaming_initialAckDelayLineEdit; + + QCheckBox * i2p_streaming_answerPingsCheckBox; + + QLabel * i2cp_leaseSetTypeLabel; + QLineEdit * i2cp_leaseSetTypeLineEdit; + + QLabel * i2cp_leaseSetEncTypeLabel; + QLineEdit * i2cp_leaseSetEncTypeLineEdit; + + QLabel * i2cp_leaseSetPrivKeyLabel; + QLineEdit * i2cp_leaseSetPrivKeyLineEdit; + + QLabel * i2cp_leaseSetAuthTypeLabel; + QLineEdit * i2cp_leaseSetAuthTypeLineEdit; + + + QString readTunnelTypeComboboxData(); + + //should be created by factory + i2p::data::SigningKeyType readSigTypeComboboxUI(QComboBox* sigTypeComboBox); + +public: + //returns false when invalid data at UI + virtual bool applyDataFromUIToTunnelConfig() { + if(!isValidSingleLine(nameLineEdit)){ + setGroupBoxTitle(QApplication::translate("tunPage", "invalid_tunnel_name")); + return false; + } + if(!isValidSingleLine(inbound_lengthLineEdit))return false; + if(!isValidSingleLine(inbound_quantityLineEdit))return false; + if(!isValidSingleLine(outbound_lengthLineEdit))return false; + if(!isValidSingleLine(outbound_quantityLineEdit))return false; + if(!isValidSingleLine(crypto_tagsToSendLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetAuthTypeLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetEncTypeLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetPrivKeyLineEdit))return false; + if(!isValidSingleLine(i2cp_leaseSetTypeLineEdit))return false; + if(!isValidSingleLine(i2p_streaming_initialAckDelayLineEdit))return false; + setGroupBoxTitle(nameLineEdit->text()); + tunnelConfig->setName(nameLineEdit->text().toStdString()); + tunnelConfig->setType(readTunnelTypeComboboxData()); + I2CPParameters& i2cpParams=tunnelConfig->getI2cpParameters(); + i2cpParams.setInbound_length(inbound_lengthLineEdit->text()); + i2cpParams.setInbound_quantity(inbound_quantityLineEdit->text()); + i2cpParams.setOutbound_length(outbound_lengthLineEdit->text()); + i2cpParams.setOutbound_quantity(outbound_quantityLineEdit->text()); + i2cpParams.setCrypto_tagsToSend(crypto_tagsToSendLineEdit->text()); + i2cpParams.set_i2cp_leaseSetAuthType(i2cp_leaseSetAuthTypeLineEdit->text()); + i2cpParams.set_i2cp_leaseSetEncType(i2cp_leaseSetEncTypeLineEdit->text()); + i2cpParams.set_i2cp_leaseSetPrivKey(i2cp_leaseSetPrivKeyLineEdit->text()); + i2cpParams.set_i2cp_leaseSetType(i2cp_leaseSetTypeLineEdit->text()); + i2cpParams.set_i2p_streaming_answerPings(i2p_streaming_answerPingsCheckBox->isChecked()); + i2cpParams.set_i2p_streaming_initialAckDelay(i2p_streaming_initialAckDelayLineEdit->text()); + return true; + } +protected: + void setupTunnelPane( + TunnelConfig* tunnelConfig, + QGroupBox *tunnelGroupBox, + QWidget* gridLayoutWidget_2, QComboBox * tunnelTypeComboBox, + QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height, int h); + void appendControlsForI2CPParameters(I2CPParameters& i2cpParameters, int& gridIndex); +public: + int height() { + return gridLayoutWidget_2?gridLayoutWidget_2->height():0; + } + +protected slots: + virtual void setGroupBoxTitle(const QString & title)=0; +private: + void retranslateTunnelForm(TunnelPane& ui) { + ui.deletePushButton->setText(QApplication::translate("tunForm", "Delete Tunnel", 0)); + ui.nameLabel->setText(QApplication::translate("tunForm", "Tunnel name:", 0)); + } + + void retranslateI2CPParameters() { + inbound_lengthLabel->setText(QApplication::translate("tunForm", "Number of hops of an inbound tunnel:", 0));; + outbound_lengthLabel->setText(QApplication::translate("tunForm", "Number of hops of an outbound tunnel:", 0));; + inbound_quantityLabel->setText(QApplication::translate("tunForm", "Number of inbound tunnels:", 0));; + outbound_quantityLabel->setText(QApplication::translate("tunForm", "Number of outbound tunnels:", 0));; + crypto_tagsToSendLabel->setText(QApplication::translate("tunForm", "Number of ElGamal/AES tags to send:", 0));; + explicitPeersLabel->setText(QApplication::translate("tunForm", "List of comma-separated b64 addresses of peers to use:", 0));; + i2p_streaming_initialAckDelayLabel->setText(QApplication::translate("tunForm", "Milliseconds to wait before sending Ack:", 0)); + i2p_streaming_answerPingsCheckBox->setText(QApplication::translate("tunForm", "Enable sending pongs", 0)); + i2cp_leaseSetTypeLabel->setText(QApplication::translate("tunForm", "Type of LeaseSet to be sent. 1, 3 or 5:", 0)); + i2cp_leaseSetEncTypeLabel->setText(QApplication::translate("tunForm", "Comma-separ. encr. types to be used in LeaseSet type 3 or 5:", 0)); + i2cp_leaseSetPrivKeyLabel->setText(QApplication::translate("tunForm", "Decryption key for encrypted LeaseSet in base64. PSK or private DH:", 0)); + i2cp_leaseSetAuthTypeLabel->setText(QApplication::translate("tunForm", "Auth type for encrypted LeaseSet. 0 - no auth, 1 - DH, 2 - PSK:", 0)); + } +protected: + bool isValidSingleLine(QLineEdit* widget); +}; + +#endif // TUNNELPANE_H diff --git a/src/TunnelsPageUpdateListener.h b/src/TunnelsPageUpdateListener.h new file mode 100644 index 0000000..83b4e9f --- /dev/null +++ b/src/TunnelsPageUpdateListener.h @@ -0,0 +1,12 @@ +#ifndef TUNNELSPAGEUPDATELISTENER_H +#define TUNNELSPAGEUPDATELISTENER_H + +class TunnelConfig; + +class TunnelsPageUpdateListener { +public: + virtual void updated(std::string oldName, TunnelConfig* tunConf)=0; + virtual void needsDeleting(std::string oldName)=0; +}; + +#endif // TUNNELSPAGEUPDATELISTENER_H diff --git a/src/generalsettingswidget.ui b/src/generalsettingswidget.ui new file mode 100644 index 0000000..e81d6f1 --- /dev/null +++ b/src/generalsettingswidget.ui @@ -0,0 +1,3810 @@ + + + GeneralSettingsContentsForm + + + + 0 + 0 + 679 + 4152 + + + + + 0 + 0 + + + + GeneralSettingsContentsForm + + + QGroupBox { + font: bold; + border: 1px solid silver; + border-radius: 6px; + margin-top: 6px; +} + +QGroupBox::title { + subcontrol-origin: margin; + left: 7px; + padding: 0px 5px 0px 5px; +} + + + + + + 0 + 0 + 679 + 4434 + + + + + QLayout::SetDefaultConstraint + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + General options + + + + + + + + 0 + 0 + + + + + 0 + 80 + + + + + 16777215 + 80 + + + + QGroupBox { + font: bold; + border: 1px solid silver; + border-radius: 6px; + margin-top: 6px; +} + +QGroupBox::title { + subcontrol-origin: margin; + left: 7px; + padding: 0px 5px 0px 5px; +} + + + + Configuration file: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 12 + 19 + 651 + 51 + + + + + + + QLayout::SetMinAndMaxSize + + + 10 + + + 10 + + + 10 + + + 10 + + + + + + + + + 0 + 27 + + + + + 0 + 0 + + + + + 16777215 + 27 + + + + Browse… + + + + + + + + + + + + + + 0 + 80 + + + + + 16777215 + 80 + + + + Data folder (for storage of i2pd data — RI, keys, peer profiles, …): + + + + + 12 + 19 + 651 + 51 + + + + + 10 + + + 10 + + + 10 + + + 10 + + + + + QLayout::SetMaximumSize + + + + + + + + Browse… + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 80 + + + + + 16777215 + 80 + + + + Pid file: + + + + + 12 + 19 + 651 + 51 + + + + + 10 + + + 10 + + + 10 + + + 10 + + + + + QLayout::SetMaximumSize + + + + + + + + + 0 + 0 + + + + + 0 + 27 + + + + + 16777215 + 27 + + + + Browse… + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 80 + + + + + 16777215 + 80 + + + + Tunnels configuration file: + + + + + 12 + 19 + 651 + 51 + + + + + 10 + + + 10 + + + 10 + + + 10 + + + + + QLayout::SetMaximumSize + + + + + + + + + 0 + 0 + + + + + 0 + 27 + + + + + 16777215 + 27 + + + + Browse… + + + + + + + + + + + + + + 0 + 130 + + + + + 16777215 + 130 + + + + Logging + + + Qt::AlignJustify|Qt::AlignTop + + + + + -1 + 19 + 661 + 91 + + + + + QLayout::SetMinAndMaxSize + + + + + QLayout::SetMaximumSize + + + + + Destination: + + + + + + + + + + Edit + + + + + + + Log file: + + + + + + + + + + Browse… + + + + + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + Log level: + + + + + + + + None + + + + + Error + + + + + Warn + + + + + Info + + + + + Debug + + + + + + + + Edit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Write full CLF-formatted date and time to log + + + + + + + + + + + + 0 + 0 + + + + + 0 + 417 + + + + + 16777215 + 417 + + + + Router options + + + + + 0 + 20 + 661 + 397 + + + + + + + Enable communication through ipv4 + + + + + + + Enable communication through ipv6 + + + + + + + Router will not accept transit tunnels at startup + + + + + + + Router will be floodfill + + + + + + + Enable SSU transport protocol (use UDP) + + + + + + + Assume we are behind NAT + + + + + + + Check remote RI for being in blacklist of reserved IP ranges + + + + + + + + + Bandwidth limit (integer or a letter): + + + + + + + + + + KBps + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Family (name of a family router belongs to): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetMaximumSize + + + + + NetID (network ID router belongs to. The main I2P ID is 2): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Network interface to bind to for IPv4: + + + + + + + + + + + + + + Network interface to bind to for IPv6: + + + + + + + + + + + + + + Max % of bandwidth limit for transit. 0-100: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 230 + + + + + 16777215 + 230 + + + + HTTP webconsole + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 321 + 22 + + + + Enable basic HTTP auth + + + + + + 60 + 120 + 601 + 31 + + + + + + + Username: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 60 + 150 + 601 + 31 + + + + + + + Password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 1 + 182 + 661 + 21 + + + + Enable strict host checking on web UI + + + + + + -1 + 200 + 661 + 27 + + + + + + + Expected hostname for web UI: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 78 + + + + + 16777215 + 78 + + + + Addressbook settings + + + + + 0 + 20 + 661 + 31 + + + + + + + Addressbook default subscription URL for initial setup: + + + + + + + + + + + + 0 + 50 + 661 + 31 + + + + + + + Addressbook subscriptions URLs, separated by comma: + + + + + + + + + + + + + + + 0 + 190 + + + + + 16777215 + 190 + + + + Reseeding + + + + + 0 + 20 + 661 + 22 + + + + Request SU3 signature verification + + + + + + 0 + 40 + 661 + 31 + + + + + + + SU3 file to reseed from: + + + + + + + + + + Browse… + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Reseed URLs, separated by comma: + + + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Path to local .zip file to reseed from: + + + + + + + + + + Browse... + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Minimum number of known routers before requesting reseed: + + + + + + + + + + Qt::Horizontal + + + + 50 + 20 + + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + URL for https/socks reseed proxy: + + + + + + + + + + + + + + + 0 + 68 + + + + + 16777215 + 68 + + + + UPnP + + + + + 0 + 20 + 97 + 22 + + + + Enable + + + + + + 0 + 40 + 661 + 31 + + + + + + + Name i2pd appears in UPnP forwardings list: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + BOB interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 170 + + + + + 16777215 + 170 + + + + Trust options + + + + + 0 + 20 + 661 + 21 + + + + Enable explicit trust options + + + + + + 390 + 40 + 271 + 23 + + + + + + + 0 + 40 + 391 + 42 + + + + Make direct I2P connections only to +routers in specified Family: + + + + + + 0 + 82 + 661 + 42 + + + + Make direct I2P connections only to routers specified here. +Comma separated list of base64 identities: + + + + + + 0 + 124 + 661 + 23 + + + + + + + 0 + 147 + 661 + 21 + + + + Should we hide our router from other routers? + + + + + + + + + 0 + 400 + + + + + 16777215 + 400 + + + + HTTP proxy + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Keys file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Inbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 190 + 661 + 31 + + + + + + + Inbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 220 + 661 + 31 + + + + + + + Outbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 250 + 661 + 31 + + + + + + + Outbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Signature type: + + + + + + + + + + Edit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 280 + 661 + 23 + + + + Enable address helper (jump) + + + + + + 0 + 300 + 661 + 95 + + + + + + + + + HTTP proxy upstream out proxy URL (like http://false.i2p): + + + + + + + + + + + + + + Type of LeaseSet to be sent. 1, 3 or 5: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Comma-separated encryption types to be used in LeaseSet type 3 or 5: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 121 + + + + + 16777215 + 121 + + + + SAM interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 621 + 23 + + + + Single thread for all SAM sessions + + + + + + + + + 0 + 0 + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + Router external address (for incoming connections) + + + Qt::AlignJustify|Qt::AlignTop + + + + + 0 + 20 + 661 + 81 + + + + + QLayout::SetMinAndMaxSize + + + + + QLayout::SetMinAndMaxSize + + + + + Host: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetMinAndMaxSize + + + + + Port (leave 0 to auto-assign): + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 108 + + + + + 16777215 + 108 + + + + Limits + + + + + 0 + 20 + 661 + 31 + + + + + + + Maximum number of transit tunnels: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 50 + 661 + 31 + + + + + + + Maximum number of open files (0 — use system limit): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 80 + 661 + 31 + + + + + + + Maximum size of core file in Kb (0 — use system limit): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 128 + + + + + 16777215 + 128 + + + + Nettime options + + + + + 0 + 20 + 671 + 101 + + + + + QLayout::SetMinAndMaxSize + + + + + Enable NTP sync + + + + + + + + + Comma-separated list of NTP servers: + + + + + + + + + + + + + + NTP time sync interval in hours: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 225 + + + + + 16777215 + 225 + + + + NTCP2 options + + + + + -1 + 19 + 671 + 191 + + + + + QLayout::SetMinAndMaxSize + + + + + Enable NTCP2 + + + + + + + Enable incoming NTCP2 connections + + + + + + + + + Port to listen for incoming NTCP2 connections: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + External IPv6 address for incoming connections: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Specify proxy server for NTCP2: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Proxy server should be http://address:port or socks://address:port + + + + + + + + + + + + 0 + 189 + + + + + 16777215 + 189 + + + + I2PControl interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Certificate file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Key file: + + + + + + + + + + Browse… + + + + + + + + + + + + 0 + 44 + + + + + 16777215 + 44 + + + + Cryptography + + + + + 0 + 20 + 661 + 22 + + + + Use ElGamal precomputed tables + + + + + + + + + 0 + 121 + + + + + 16777215 + 121 + + + + I2CP interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 651 + 23 + + + + Single thread for all I2CP sessions + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Ports + + + + + + + + 0 + 500 + + + + + 16777215 + 500 + + + + Socks proxy + + + + + 9 + 20 + 661 + 470 + + + + + 10 + + + 10 + + + 10 + + + 10 + + + + + Enabled + + + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Keys file: + + + + + + + + + + Browse… + + + + + + + + + + + Signature type: + + + + + + + + + + Edit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Inbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Inbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Outbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Outbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + 0 + + + + + Outproxy enabled + + + + + + + + + + + Outproxy address: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Outproxy port: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Type of LeaseSet to be sent. 1, 3 or 5: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Comma-separated encryption types to be used in LeaseSet type 3 or 5: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 145 + + + + + 16777215 + 300 + + + + Websocket Server + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + -1 + 19 + 681 + 124 + + + + + QLayout::SetDefaultConstraint + + + 10 + + + 10 + + + 10 + + + 10 + + + + + Enable websocket server + + + + + + + + + Address to bind websocket server on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Port to bind websocket server on: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Various options + + + + + + + + 0 + 0 + + + + + 0 + 160 + + + + + 16777215 + 160 + + + + Exploratory Tunnels + + + + + -1 + 19 + 671 + 131 + + + + + QLayout::SetMinAndMaxSize + + + + + + + Exploratory inbound tunnels length: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Exploratory inbound tunnels quantity: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Exploratory outbound tunnels length: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Exploratory outbound tunnels quantity: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 56 + + + + + 16777215 + 56 + + + + Persist profiles + + + + + 0 + 20 + 681 + 31 + + + + + QLayout::SetMinAndMaxSize + + + + + Enable peer profile persisting to disk + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Windows-specific options + + + + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Insomnia (prevent system from sleeping) + + + + + + + + + diff --git a/src/i2pd b/src/i2pd new file mode 160000 index 0000000..9e5935a --- /dev/null +++ b/src/i2pd @@ -0,0 +1 @@ +Subproject commit 9e5935aea5c979a3a41a1c200811687b48356f68 diff --git a/src/i2pd.qrc b/src/i2pd.qrc new file mode 100644 index 0000000..4e5523e --- /dev/null +++ b/src/i2pd.qrc @@ -0,0 +1,6 @@ + + + resources/icons/mask.ico + resources/images/icon.png + + diff --git a/src/i2pd.rc b/src/i2pd.rc new file mode 100644 index 0000000..2428ab1 --- /dev/null +++ b/src/i2pd.rc @@ -0,0 +1,32 @@ +IDI_ICON1 ICON DISCARDABLE "resources/icons/mask.ico" + +#include // needed for VERSIONINFO +#include "i2pd/libi2pd/version.h" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH +PRODUCTVERSION I2P_VERSION_MAJOR,I2P_VERSION_MINOR,I2P_VERSION_MICRO,I2P_VERSION_PATCH +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // U.S. English - multilingual (hex) + BEGIN + VALUE "CompanyName", "PurpleI2P" + VALUE "FileDescription", "I2Pd Qt" + VALUE "FileVersion", I2PD_VERSION + VALUE "InternalName", "i2pd-qt" + VALUE "LegalCopyright", "Copyright (C) 2013-2020, The PurpleI2P Project" + VALUE "LegalTrademarks1", "Distributed under the BSD 3-Clause software license, see the accompanying file COPYING or https://opensource.org/licenses/BSD-3-Clause." + VALUE "OriginalFilename", "i2pd_qt.exe" + VALUE "ProductName", "i2pd-qt" + VALUE "ProductVersion", I2P_VERSION + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) + END +END diff --git a/src/logviewermanager.cpp b/src/logviewermanager.cpp new file mode 100644 index 0000000..f110db9 --- /dev/null +++ b/src/logviewermanager.cpp @@ -0,0 +1,45 @@ +#include "logviewermanager.h" + +LogViewerManager::LogViewerManager(std::shared_ptr logStream_, + QPlainTextEdit* logTextEdit_, + QObject *parent) : + QObject(parent), + logStream(logStream_), + logTextEdit(logTextEdit_), + controllerForBgThread(nullptr) +{ + assert(logTextEdit!=nullptr); + controllerForBgThread=new i2pd::qt::logviewer::Controller(*this); +} + +namespace i2pd { +namespace qt { +namespace logviewer { + +QString Worker::pollAndShootATimerForInfiniteRetries() { + std::shared_ptr logStream=logViewerManager.getLogStream(); + if(!logStream)return ""; + std::streamsize MAX_SZ=64*1024; + char*buf=(char*)malloc(MAX_SZ*sizeof(char)); + if(buf==nullptr)return ""; + std::streamsize read=logStream->readsome(buf, MAX_SZ); + if(read<0)read=0; + QString ret=QString::fromUtf8(buf, read); + free(buf); + return ret; +} + +Controller::Controller(LogViewerManager ¶meter1):logViewerManager(parameter1) { + Worker *worker = new Worker(parameter1); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &Controller::operate1, worker, &Worker::doWork1); + connect(worker, &Worker::resultReady, + ¶meter1, &LogViewerManager::appendPlainText_atGuiThread); + workerThread.start(); + timerId=startTimer(100/*millis*/); +} + +} +} +} diff --git a/src/logviewermanager.h b/src/logviewermanager.h new file mode 100644 index 0000000..857d355 --- /dev/null +++ b/src/logviewermanager.h @@ -0,0 +1,130 @@ +#ifndef LOGVIEWERMANAGER_H +#define LOGVIEWERMANAGER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "FS.h" +#include "Log.h" + +class LogViewerManager; + +namespace i2pd { +namespace qt { +namespace logviewer { + +class Worker : public QObject +{ + Q_OBJECT +private: + LogViewerManager &logViewerManager; +public: + Worker(LogViewerManager ¶meter1):logViewerManager(parameter1){} +private: + QString pollAndShootATimerForInfiniteRetries(); + +public slots: + void doWork1() { + /* ... here is the expensive or blocking operation ... */ + QString read=pollAndShootATimerForInfiniteRetries(); + emit resultReady(read); + } + +signals: + void resultReady(QString read); +}; + +class Controller : public QObject +{ + Q_OBJECT + QThread workerThread; + LogViewerManager& logViewerManager; + int timerId; +public: + Controller(LogViewerManager ¶meter1); + ~Controller() { + if(timerId!=0)killTimer(timerId); + workerThread.quit(); + workerThread.wait(); + } +signals: + void operate1(); +protected: + void timerEvent(QTimerEvent */*event*/) { + emit operate1(); + } +}; + +} +} +} + +class LogViewerManager : public QObject +{ + Q_OBJECT +private: + std::shared_ptr logStream; + QPlainTextEdit* logTextEdit; + i2pd::qt::logviewer::Controller* controllerForBgThread; +public: + //also starts a bg thread (QTimer) polling logStream->readsome(buf, n) + explicit LogViewerManager(std::shared_ptr logStream_, + QPlainTextEdit* logTextEdit_, + QObject *parent); + //also deallocs the bg thread (QTimer) + virtual ~LogViewerManager(){} + const i2pd::qt::logviewer::Controller& getControllerForBgThread() { + assert(controllerForBgThread!=nullptr); + return *controllerForBgThread; + } + const QPlainTextEdit* getLogTextEdit(){ return logTextEdit; } + const std::shared_ptr getLogStream(){ return logStream; } +signals: + +public slots: + //void appendFromNonGuiThread(std::string read) { + //} +public slots: + void appendPlainText_atGuiThread(QString plainText) { + if(plainText.length()==0)return; + assert(logTextEdit!=nullptr); + int scrollPosVert =logTextEdit->verticalScrollBar()->value(); + int scrollPosHoriz=logTextEdit->horizontalScrollBar()->value(); + int scrollPosVertMax =logTextEdit->verticalScrollBar()->maximum(); + const int MAX_LINES=10*1024; + logTextEdit->setMaximumBlockCount(MAX_LINES); + //logTextEdit->appendPlainText(plainText); + //navigate the window to the end + //QTextCursor cursor = logTextEdit->textCursor(); + //cursor.movePosition(QTextCursor::MoveOperation::End); + //logTextEdit->setTextCursor(cursor); + //QTextCursor prev_cursor = logTextEdit->textCursor(); + logTextEdit->moveCursor(QTextCursor::End); + logTextEdit->insertPlainText(plainText); + if(/*prev_cursor.atEnd()*/scrollPosVert==scrollPosVertMax){ + //logTextEdit->moveCursor(QTextCursor::End); + scrollPosVert =logTextEdit->verticalScrollBar()->maximum(); + scrollPosHoriz=logTextEdit->horizontalScrollBar()->minimum(); + } + //else + // logTextEdit->setTextCursor(prev_cursor); + logTextEdit->verticalScrollBar()->setValue(scrollPosVert); + logTextEdit->horizontalScrollBar()->setValue(scrollPosHoriz); + } + /* + void replaceText_atGuiThread() { + assert(logTextEdit!=nullptr); + logTextEdit->setText(QString::fromStdString(nav.getContent())); + } + */ +}; + +#endif // LOGVIEWERMANAGER_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..7aa868f --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,1126 @@ +#include "mainwindow.h" +#include "I2pdQtUtil.h" +#include "AboutDialog.h" +#include "ui_mainwindow.h" +#include "ui_statusbuttons.h" +#include "ui_routercommandswidget.h" +#include "ui_generalsettingswidget.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "RouterContext.h" +#include "Config.h" +#include "FS.h" +#include "Log.h" +#include "RouterContext.h" +#include "Transports.h" + +#include "HTTPServer.h" + +#ifndef ANDROID +# include +#endif + +#include "DaemonQT.h" +#include "SignatureTypeComboboxFactory.h" + +#include "logviewermanager.h" + +#include "DelayedSaveManagerImpl.h" +#include "SaverImpl.h" + + +std::string programOptionsWriterCurrentSection; + +MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *parent) : + QMainWindow(parent) + ,currentLocalDestinationB32("") + ,logStream(logStream_) + ,delayedSaveManagerPtr(new DelayedSaveManagerImpl()) + ,dataSerial(DelayedSaveManagerImpl::INITIAL_DATA_SERIAL) + ,wasSelectingAtStatusMainPage(false) + ,showHiddenInfoStatusMainPage(false) + ,logViewerManagerPtr(nullptr) +#ifndef ANDROID + ,quitting(false) +#endif + ,ui(new Ui::MainWindow) + ,statusButtonsUI(new Ui::StatusButtonsForm) + ,routerCommandsUI(new Ui::routerCommandsWidget) + ,uiSettings(new Ui::GeneralSettingsContentsForm) + ,routerCommandsParent(new QWidget(this)) + ,widgetlocks() + ,i2pController(nullptr) + ,configItems() + ,datadir() + ,confpath() + ,tunconfpath() + ,tunnelConfigs() + ,tunnelsPageUpdateListener(this) + ,saverPtr(new SaverImpl(this, &configItems, &tunnelConfigs)) + +{ + assert(delayedSaveManagerPtr!=nullptr); + assert(saverPtr!=nullptr); + + ui->setupUi(this); + statusButtonsUI->setupUi(ui->statusButtonsPane); + routerCommandsUI->setupUi(routerCommandsParent); + uiSettings->setupUi(ui->settingsContents); + + ui->aboutHrefLabel->setText("

" + "i2pd_qt
Version " I2PD_VERSION " · About...

"); + + routerCommandsParent->hide(); + ui->verticalLayout_2->addWidget(routerCommandsParent); + //,statusHtmlUI(new Ui::StatusHtmlPaneForm) + //statusHtmlUI->setupUi(lastStatusWidgetui->statusWidget); + ui->statusButtonsPane->setFixedSize(171,300); + ui->verticalLayout->setGeometry(QRect(0,0,171,ui->verticalLayout->geometry().height())); + //ui->statusButtonsPane->adjustSize(); + //ui->centralWidget->adjustSize(); + setWindowTitle(QApplication::translate("AppTitle","I2PD")); + + //TODO handle resizes and change the below into resize() call + constexpr auto WINDOW_HEIGHT = 610; + setFixedHeight(WINDOW_HEIGHT); + ui->centralWidget->setFixedHeight(WINDOW_HEIGHT); + onResize(); + + ui->stackedWidget->setCurrentIndex(0); + ui->settingsScrollArea->resize(uiSettings->settingsContentsQVBoxLayout->sizeHint().width()+10,380); + //QScrollBar* const barSett = ui->settingsScrollArea->verticalScrollBar(); + constexpr auto w = 683; + constexpr auto h = 4550; + ui->settingsContents->setFixedSize(w, h); + ui->settingsContents->setGeometry(QRect(0,0,w,h)); + + /* + QPalette pal(palette()); + pal.setColor(QPalette::Background, Qt::red); + ui->settingsContents->setAutoFillBackground(true); + ui->settingsContents->setPalette(pal); + */ + QPalette pal(palette()); + pal.setColor(QPalette::Background, Qt::red); + ui->wrongInputLabel->setAutoFillBackground(true); + ui->wrongInputLabel->setPalette(pal); + ui->wrongInputLabel->setMaximumHeight(ui->wrongInputLabel->sizeHint().height()); + ui->wrongInputLabel->setVisible(false); + + settingsTitleLabelNominalHeight = ui->settingsTitleLabel->height(); +#ifndef ANDROID + createActions(); + createTrayIcon(); +#endif + + textBrowser = new TextBrowserTweaked1(this); + //textBrowser->setOpenExternalLinks(false); + textBrowser->setOpenLinks(false); + /*textBrowser->setTextInteractionFlags(textBrowser->textInteractionFlags()| + Qt::LinksAccessibleByMouse|Qt::LinksAccessibleByKeyboard| + Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);*/ + ui->verticalLayout_2->addWidget(textBrowser); + childTextBrowser = new TextBrowserTweaked1(this); + //childTextBrowser->setOpenExternalLinks(false); + childTextBrowser->setOpenLinks(false); + connect(textBrowser, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(anchorClickedHandler(const QUrl&))); + connect(childTextBrowser, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(anchorClickedHandler(const QUrl&))); + pageWithBackButton = new PageWithBackButton(this, childTextBrowser); + ui->verticalLayout_2->addWidget(pageWithBackButton); + pageWithBackButton->hide(); + connect(pageWithBackButton, SIGNAL(backReleased()), this, SLOT(backClickedFromChild())); + scheduleStatusPageUpdates(); + + QObject::connect(ui->statusPagePushButton, SIGNAL(released()), this, SLOT(showStatusMainPage())); + showStatusMainPage(); + QObject::connect(statusButtonsUI->mainPagePushButton, SIGNAL(released()), this, SLOT(showStatusMainPage())); + QObject::connect(statusButtonsUI->routerCommandsPushButton, SIGNAL(released()), this, SLOT(showStatus_commands_Page())); + QObject::connect(statusButtonsUI->localDestinationsPushButton, SIGNAL(released()), this, SLOT(showStatus_local_destinations_Page())); + QObject::connect(statusButtonsUI->leasesetsPushButton, SIGNAL(released()), this, SLOT(showStatus_leasesets_Page())); + QObject::connect(statusButtonsUI->tunnelsPushButton, SIGNAL(released()), this, SLOT(showStatus_tunnels_Page())); + QObject::connect(statusButtonsUI->transitTunnelsPushButton, SIGNAL(released()), this, SLOT(showStatus_transit_tunnels_Page())); + QObject::connect(statusButtonsUI->transportsPushButton, SIGNAL(released()), this, SLOT(showStatus_transports_Page())); + QObject::connect(statusButtonsUI->i2pTunnelsPushButton, SIGNAL(released()), this, SLOT(showStatus_i2p_tunnels_Page())); + QObject::connect(statusButtonsUI->samSessionsPushButton, SIGNAL(released()), this, SLOT(showStatus_sam_sessions_Page())); + + QObject::connect(textBrowser, SIGNAL(mouseReleased()), this, SLOT(statusHtmlPageMouseReleased())); + QObject::connect(textBrowser, SIGNAL(selectionChanged()), this, SLOT(statusHtmlPageSelectionChanged())); + + QObject::connect(routerCommandsUI->runPeerTestPushButton, SIGNAL(released()), this, SLOT(runPeerTest())); + QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit())); + QObject::connect(routerCommandsUI->declineTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(disableTransit())); + + QObject::connect(ui->aboutHrefLabel, SIGNAL(linkActivated(const QString &)), this, SLOT(showAboutBox(const QString &))); + + QObject::connect(ui->logViewerPushButton, SIGNAL(released()), this, SLOT(showLogViewerPage())); + + QObject::connect(ui->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage())); + + QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage())); + QObject::connect(ui->restartPagePushButton, SIGNAL(released()), this, SLOT(showRestartPage())); + QObject::connect(ui->quitPagePushButton, SIGNAL(released()), this, SLOT(showQuitPage())); + + QObject::connect(ui->fastQuitPushButton, SIGNAL(released()), this, SLOT(handleQuitButton())); + QObject::connect(ui->gracefulQuitPushButton, SIGNAL(released()), this, SLOT(handleGracefulQuitButton())); + + QObject::connect(ui->doRestartI2PDPushButton, SIGNAL(released()), this, SLOT(handleDoRestartButton())); + +# define OPTION(section,option,defaultValueGetter) ConfigOption(QString(section),QString(option)) + + initFileChooser( OPTION("","conf",[](){return "";}), uiSettings->configFileLineEdit, uiSettings->configFileBrowsePushButton, false, true); + initFileChooser( OPTION("","tunconf",[](){return "";}), uiSettings->tunnelsConfigFileLineEdit, uiSettings->tunnelsConfigFileBrowsePushButton, false); + initFileChooser( OPTION("","pidfile",[]{return "";}), uiSettings->pidFileLineEdit, uiSettings->pidFileBrowsePushButton, false); + + uiSettings->logDestinationComboBox->clear(); + uiSettings->logDestinationComboBox->insertItems(0, QStringList() + << QApplication::translate("MainWindow", "syslog", 0) + << QApplication::translate("MainWindow", "stdout", 0) + << QApplication::translate("MainWindow", "file", 0) + ); + initLogDestinationCombobox( OPTION("","log",[]{return "";}), uiSettings->logDestinationComboBox); +#ifdef I2PD_QT_RELEASE + uiSettings->logDestinationComboBox->setEnabled(false); // #1593 +#endif + + logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), uiSettings->logFileLineEdit, uiSettings->logFileBrowsePushButton, false); + initLogLevelCombobox(OPTION("","loglevel",[]{return "";}), uiSettings->logLevelComboBox); + + QObject::connect(uiSettings->logLevelComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(syncLogLevel(int))); + + initCheckBox( OPTION("","logclftime",[]{return "false";}), uiSettings->logclftimeCheckBox);//"Write full CLF-formatted date and time to log (default: write only time)" + initFolderChooser( OPTION("","datadir",[]{return "";}), uiSettings->dataFolderLineEdit, uiSettings->dataFolderBrowsePushButton); + initIPAddressBox( OPTION("","host",[]{return "";}), uiSettings->routerExternalHostLineEdit, tr("Router external address -> Host")); + initTCPPortBox( OPTION("","port",[]{return "";}), uiSettings->routerExternalPortLineEdit, tr("Router external address -> Port")); + daemonOption=initNonGUIOption( OPTION("","daemon",[]{return "";})); + serviceOption=initNonGUIOption( OPTION("","service",[]{return "";})); + initStringBox( OPTION("","ifname4",[]{return "";}), uiSettings->ifname4LineEdit);//Network interface to bind to for IPv4 + initStringBox( OPTION("","ifname6",[]{return "";}), uiSettings->ifname6LineEdit);//Network interface to bind to for IPv6 + initCheckBox( OPTION("","nat",[]{return "true";}), uiSettings->natCheckBox);//If true, assume we are behind NAT. true by default + initCheckBox( OPTION("","ipv4",[]{return "true";}), uiSettings->ipv4CheckBox);//Enable communication through IPv4. true by default + initCheckBox( OPTION("","ipv6",[]{return "false";}), uiSettings->ipv6CheckBox); + initCheckBox( OPTION("","notransit",[]{return "false";}), uiSettings->notransitCheckBox); + initCheckBox( OPTION("","floodfill",[]{return "false";}), uiSettings->floodfillCheckBox); + initStringBox( OPTION("","bandwidth",[]{return "";}), uiSettings->bandwidthLineEdit); + initIntegerBox( OPTION("","share",[]{return "100";}), uiSettings->shareLineEdit, tr("Share"));//Max % of bandwidth limit for transit. 0-100. 100 by default + initStringBox( OPTION("","family",[]{return "";}), uiSettings->familyLineEdit); + initIntegerBox( OPTION("","netid",[]{return "2";}), uiSettings->netIdLineEdit, tr("NetID")); + initCheckBox( OPTION("","ssu",[]{return "true";}), uiSettings->ssuCheckBox);//Enable SSU transport protocol (use UDP). true by default + initCheckBox( OPTION("","reservedrange",[]{return "true";}), uiSettings->reservedrange_checkbox); + +#ifdef Q_OS_WIN + initNonGUIOption( OPTION("","svcctl",[]{return "";})); + initCheckBox( OPTION("","insomnia",[]{return "";}), uiSettings->insomniaCheckBox); + initNonGUIOption( OPTION("","close",[]{return "";})); +#else + uiSettings->insomniaCheckBox->setEnabled(false); +#endif + + initCheckBox( OPTION("http","enabled",[]{return "true";}), uiSettings->webconsoleEnabledCheckBox); + initIPAddressBox( OPTION("http","address",[]{return "";}), uiSettings->webconsoleAddrLineEdit, tr("HTTP webconsole -> IP address")); + initTCPPortBox( OPTION("http","port",[]{return "7070";}), uiSettings->webconsolePortLineEdit, tr("HTTP webconsole -> Port")); + initCheckBox( OPTION("http","auth",[]{return "";}), uiSettings->webconsoleBasicAuthCheckBox); + initStringBox( OPTION("http","user",[]{return "i2pd";}), uiSettings->webconsoleUserNameLineEditBasicAuth); + initStringBox( OPTION("http","pass",[]{return "";}), uiSettings->webconsolePasswordLineEditBasicAuth); + initCheckBox( OPTION("http","strictheaders",[]{return "true";}), uiSettings->httpStrictHeadersCheckBox);//Enable strict host checking on WebUI. true by default + initStringBox( OPTION("http","hostname",[]{return "localhost";}), uiSettings->httpHostnameLineEdit);//Expected hostname for WebUI (default: localhost) + + initCheckBox( OPTION("httpproxy","enabled",[]{return "";}), uiSettings->httpProxyEnabledCheckBox); + initIPAddressBox( OPTION("httpproxy","address",[]{return "";}), uiSettings->httpProxyAddressLineEdit, tr("HTTP proxy -> IP address")); + initTCPPortBox( OPTION("httpproxy","port",[]{return "4444";}), uiSettings->httpProxyPortLineEdit, tr("HTTP proxy -> Port")); + initCheckBox( OPTION("httpproxy","addresshelper",[]{return "true";}), uiSettings->httpProxyAddressHelperCheckBox);//Enable address helper (jump). true by default + initFileChooser( OPTION("httpproxy","keys",[]{return "";}), uiSettings->httpProxyKeyFileLineEdit, uiSettings->httpProxyKeyFilePushButton, false); + initSignatureTypeCombobox(OPTION("httpproxy","signaturetype",[]{return "7";}), uiSettings->comboBox_httpPorxySignatureType); + initStringBox( OPTION("httpproxy","inbound.length",[]{return "3";}), uiSettings->httpProxyInboundTunnelsLenLineEdit); + initStringBox( OPTION("httpproxy","inbound.quantity",[]{return "5";}), uiSettings->httpProxyInboundTunnQuantityLineEdit); + initStringBox( OPTION("httpproxy","outbound.length",[]{return "3";}), uiSettings->httpProxyOutBoundTunnLenLineEdit); + initStringBox( OPTION("httpproxy","outbound.quantity",[]{return "5";}), uiSettings->httpProxyOutboundTunnQuantityLineEdit); + initStringBox( OPTION("httpproxy","outproxy",[]{return "";}), uiSettings->httpProxyOutproxyLineEdit);//HTTP proxy upstream out proxy url (like http://false.i2p) + initStringBox( OPTION("httpproxy","i2cp.leaseSetType",[]{return "1";}), uiSettings->httpProxyI2cpLeaseSetTypeLineEdit);//Type of LeaseSet to be sent. 1, 3 or 5. 1 by default + initStringBox( OPTION("httpproxy","i2cp.leaseSetEncType",[]{return "";}), uiSettings->httpProxyI2cpLeaseSetEncTypeLineEdit);//Comma separated encryption types to be used in LeaseSet type 3 or 5 + + initCheckBox( OPTION("socksproxy","enabled",[]{return "";}), uiSettings->socksProxyEnabledCheckBox); + initIPAddressBox( OPTION("socksproxy","address",[]{return "";}), uiSettings->socksProxyAddressLineEdit, tr("Socks proxy -> IP address")); + initTCPPortBox( OPTION("socksproxy","port",[]{return "4447";}), uiSettings->socksProxyPortLineEdit, tr("Socks proxy -> Port")); + initFileChooser( OPTION("socksproxy","keys",[]{return "";}), uiSettings->socksProxyKeyFileLineEdit, uiSettings->socksProxyKeyFilePushButton, false); + initSignatureTypeCombobox(OPTION("socksproxy","signaturetype",[]{return "7";}), uiSettings->comboBox_socksProxySignatureType); + initStringBox( OPTION("socksproxy","inbound.length",[]{return "";}), uiSettings->socksProxyInboundTunnelsLenLineEdit); + initStringBox( OPTION("socksproxy","inbound.quantity",[]{return "";}), uiSettings->socksProxyInboundTunnQuantityLineEdit); + initStringBox( OPTION("socksproxy","outbound.length",[]{return "";}), uiSettings->socksProxyOutBoundTunnLenLineEdit); + initStringBox( OPTION("socksproxy","outbound.quantity",[]{return "";}), uiSettings->socksProxyOutboundTunnQuantityLineEdit); + initCheckBox( OPTION("socksproxy","outproxy.enabled",[]{return "false";}), uiSettings->socksOutproxyEnabledCheckBox); + initIPAddressBox( OPTION("socksproxy","outproxy",[]{return "127.0.0.1";}), uiSettings->outproxyAddressLineEdit, tr("Socks proxy -> Outproxy address")); + initTCPPortBox( OPTION("socksproxy","outproxyport",[]{return "9050";}), uiSettings->outproxyPortLineEdit, tr("Socks proxy -> Outproxy port")); + initStringBox( OPTION("socksproxy","i2cp.leaseSetType",[]{return "1";}), uiSettings->socksProxyI2cpLeaseSetTypeLineEdit);//Type of LeaseSet to be sent. 1, 3 or 5. 1 by default + initStringBox( OPTION("socksproxy","i2cp.leaseSetEncType",[]{return "";}), uiSettings->socksProxyI2cpLeaseSetEncTypeLineEdit);//Comma separated encryption types to be used in LeaseSet type 3 or 5 + + initCheckBox( OPTION("sam","enabled",[]{return "false";}), uiSettings->samEnabledCheckBox); + initIPAddressBox( OPTION("sam","address",[]{return "";}), uiSettings->samAddressLineEdit, tr("SAM -> IP address")); + initTCPPortBox( OPTION("sam","port",[]{return "7656";}), uiSettings->samPortLineEdit, tr("SAM -> Port")); + initCheckBox( OPTION("sam","singlethread",[]{return "true";}), uiSettings->samSingleThreadCheckBox);//If false every SAM session runs in own thread. true by default + + initCheckBox( OPTION("bob","enabled",[]{return "false";}), uiSettings->bobEnabledCheckBox); + initIPAddressBox( OPTION("bob","address",[]{return "";}), uiSettings->bobAddressLineEdit, tr("BOB -> IP address")); + initTCPPortBox( OPTION("bob","port",[]{return "2827";}), uiSettings->bobPortLineEdit, tr("BOB -> Port")); + + initCheckBox( OPTION("i2cp","enabled",[]{return "false";}), uiSettings->i2cpEnabledCheckBox); + initIPAddressBox( OPTION("i2cp","address",[]{return "";}), uiSettings->i2cpAddressLineEdit, tr("I2CP -> IP address")); + initTCPPortBox( OPTION("i2cp","port",[]{return "7654";}), uiSettings->i2cpPortLineEdit, tr("I2CP -> Port")); + //initCheckBox( OPTION("i2cp","singlethread",[]{return "true";}), uiSettings->i2cpSingleThreadCheckBox);//If false every I2CP session runs in own thread. true by default + + initCheckBox( OPTION("i2pcontrol","enabled",[]{return "false";}), uiSettings->i2pControlEnabledCheckBox); + initIPAddressBox( OPTION("i2pcontrol","address",[]{return "";}), uiSettings->i2pControlAddressLineEdit, tr("I2PControl -> IP address")); + initTCPPortBox( OPTION("i2pcontrol","port",[]{return "7650";}), uiSettings->i2pControlPortLineEdit, tr("I2PControl -> Port")); + initStringBox( OPTION("i2pcontrol","password",[]{return "";}), uiSettings->i2pControlPasswordLineEdit); + initFileChooser( OPTION("i2pcontrol","cert",[]{return "i2pcontrol.crt.pem";}), uiSettings->i2pControlCertFileLineEdit, uiSettings->i2pControlCertFileBrowsePushButton, true); + initFileChooser( OPTION("i2pcontrol","key",[]{return "i2pcontrol.key.pem";}), uiSettings->i2pControlKeyFileLineEdit, uiSettings->i2pControlKeyFileBrowsePushButton, true); + + initCheckBox( OPTION("upnp","enabled",[]{return "true";}), uiSettings->enableUPnPCheckBox); + initStringBox( OPTION("upnp","name",[]{return "I2Pd";}), uiSettings->upnpNameLineEdit); + + initCheckBox( OPTION("precomputation","elgamal",[]{return "false";}), uiSettings->useElGamalPrecomputedTablesCheckBox); + + initCheckBox( OPTION("reseed","verify",[]{return "";}), uiSettings->reseedVerifyCheckBox); + initFileChooser( OPTION("reseed","file",[]{return "";}), uiSettings->reseedFileLineEdit, uiSettings->reseedFileBrowsePushButton, true); + initStringBox( OPTION("reseed","urls",[]{return "";}), uiSettings->reseedURLsLineEdit); + initFileChooser( OPTION("reseed","zipfile",[]{return "";}), uiSettings->reseedZipFileLineEdit, uiSettings->reseedZipFileBrowsePushButton, true); //Path to local .zip file to reseed from + initUInt16Box( OPTION("reseed","threshold",[]{return "25";}), uiSettings->reseedThresholdNumberLineEdit, tr("reseedThreshold")); //Minimum number of known routers before requesting reseed. 25 by default + initStringBox( OPTION("reseed","proxy",[]{return "";}), uiSettings->reseedProxyLineEdit);//URL for https/socks reseed proxy + + initStringBox( OPTION("addressbook","defaulturl",[]{return "";}), uiSettings->addressbookDefaultURLLineEdit); + initStringBox( OPTION("addressbook","subscriptions",[]{return "";}), uiSettings->addressbookSubscriptionsURLslineEdit); + + initUInt16Box( OPTION("limits","transittunnels",[]{return "2500";}), uiSettings->maxNumOfTransitTunnelsLineEdit, tr("maxNumberOfTransitTunnels")); + initUInt16Box( OPTION("limits","openfiles",[]{return "0";}), uiSettings->maxNumOfOpenFilesLineEdit, tr("maxNumberOfOpenFiles")); + initUInt32Box( OPTION("limits","coresize",[]{return "0";}), uiSettings->coreFileMaxSizeNumberLineEdit, tr("coreFileMaxSize")); + + initCheckBox( OPTION("trust","enabled",[]{return "false";}), uiSettings->checkBoxTrustEnable); + initStringBox( OPTION("trust","family",[]{return "";}), uiSettings->lineEditTrustFamily); + initStringBox( OPTION("trust","routers",[]{return "";}), uiSettings->lineEditTrustRouters); + initCheckBox( OPTION("trust","hidden",[]{return "false";}), uiSettings->checkBoxTrustHidden); + + initCheckBox( OPTION("websockets","enabled",[]{return "false";}), uiSettings->checkBoxWebsocketsEnable); //Enable websocket server. Disabled by default + initIPAddressBox( OPTION("websockets","address",[]{return "127.0.0.1";}), uiSettings->websocketsAddressLineEdit, tr("Websockets -> IP address")); //Address to bind websocket server on. 127.0.0.1 by default + initTCPPortBox( OPTION("websockets","port",[]{return "7666";}), uiSettings->websocketsPortLineEdit, tr("Websockets -> Port")); //Port to bind websocket server on. 7666 by default + + initIntegerBox( OPTION("exploratory","inbound.length",[]{return "2";}), uiSettings->exploratoryInboundTunnelsLengthNumberLineEdit, tr("exploratoryInboundTunnelsLength"));//Exploratory inbound tunnels length. 2 by default + initIntegerBox( OPTION("exploratory","inbound.quantity",[]{return "3";}), uiSettings->exploratoryInboundTunnelsQuantityNumberLineEdit, tr("exploratoryInboundTunnelsQuantity"));//Exploratory inbound tunnels quantity. 3 by default + initIntegerBox( OPTION("exploratory","outbound.length",[]{return "2";}), uiSettings->exploratoryOutboundTunnelsLengthNumberLineEdit, tr("exploratoryOutboundTunnelsLength"));//Exploratory outbound tunnels length. 2 by default + initIntegerBox( OPTION("exploratory","outbound.quantity",[]{return "3";}), uiSettings->exploratoryOutboundTunnelsQuantityNumberLineEdit, tr("exploratoryOutboundTunnelsQuantity"));//Exploratory outbound tunnels length. 3 by default + + initCheckBox( OPTION("ntcp2","enabled",[]{return "true";}), uiSettings->checkBoxNtcp2Enable); //Enable NTCP2. Enabled by default + initCheckBox( OPTION("ntcp2","published",[]{return "false";}), uiSettings->checkBoxNtcp2Published); //Enable incoming NTCP2 connections. Disabled by default + initTCPPortBox( OPTION("ntcp2","port",[]{return "0";}), uiSettings->ntcp2PortLineEdit, tr("NTCP2 -> Port")); //Port to listen for incoming NTCP2 connections (default: auto) + initIPAddressBox( OPTION("ntcp2","addressv6",[]{return "::";}), uiSettings->ntcp2AddressV6LineEdit, tr("NTCP2 -> IPv6 address")); //External IPv6 for incoming connections + initStringBox( OPTION("ntcp2","proxy",[]{return "";}), uiSettings->lineEditNtcp2Proxy); //Specify proxy server for NTCP2. Should be http://address:port or socks://address:port + + initCheckBox( OPTION("nettime","enabled",[]{return "false";}), uiSettings->checkBoxNettimeEnable); //Enable NTP sync. Disabled by default + initStringBox( OPTION("nettime","ntpservers",[]{return "pool.ntp.org";}), uiSettings->lineEditNetTimeNtpServers); //Comma-separated list of NTP servers. pool.ntp.org by default + initIntegerBox( OPTION("nettime","ntpsyncinterval",[]{return "72";}), uiSettings->nettimeNtpSyncIntervalNumberLineEdit, tr("nettimeNtpSyncInterval")); //NTP time sync interval in hours. 72 by default + + initCheckBox( OPTION("persist","profiles",[]{return "true";}), uiSettings->checkBoxPersistProfiles);//Enable peer profile persisting to disk. Enabled by default +# undef OPTION + + //widgetlocks.add(new widgetlock(widget,lockbtn)); + + + // #1593 +#ifdef I2PD_QT_RELEASE + uiSettings->logDestComboEditPushButton->setEnabled(false); +#else + widgetlocks.add(new widgetlock(uiSettings->logDestinationComboBox,uiSettings->logDestComboEditPushButton)); +#endif + + widgetlocks.add(new widgetlock(uiSettings->logLevelComboBox,uiSettings->logLevelComboEditPushButton)); + widgetlocks.add(new widgetlock(uiSettings->comboBox_httpPorxySignatureType,uiSettings->httpProxySignTypeComboEditPushButton)); + widgetlocks.add(new widgetlock(uiSettings->comboBox_socksProxySignatureType,uiSettings->socksProxySignTypeComboEditPushButton)); + + loadAllConfigs(saverPtr); + + QObject::connect(saverPtr, SIGNAL(reloadTunnelsConfigAndUISignal(const QString)), + this, SLOT(reloadTunnelsConfigAndUI_QString(const QString))); + + delayedSaveManagerPtr->setSaver(saverPtr); + delayedSaveManagerPtr->start(); + + QObject::connect(uiSettings->logDestinationComboBox, SIGNAL(currentIndexChanged(const QString &)), + this, SLOT(logDestinationComboBoxValueChanged(const QString &))); + logDestinationComboBoxValueChanged(uiSettings->logDestinationComboBox->currentText()); + + ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, 451)); + + ui->tunnelsScrollAreaWidgetContents->setStyleSheet("QGroupBox { " \ + " font: bold;" \ + " border: 1px solid silver;" \ + " border-radius: 6px;" \ + " margin-top: 6px;" \ + "}" \ + "QGroupBox::title {" \ + " subcontrol-origin: margin;" \ + " left: 7px;" \ + " padding: 0px 5px 0px 5px;" \ + "}"); + + appendTunnelForms(""); + + uiSettings->configFileLineEdit->setEnabled(false); + uiSettings->configFileBrowsePushButton->setEnabled(false); + uiSettings->configFileLineEdit->setText(confpath); + uiSettings->tunnelsConfigFileLineEdit->setText(tunconfpath); + + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + item->installListeners(this); + } + + QObject::connect(uiSettings->tunnelsConfigFileLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(reloadTunnelsConfigAndUI())); + QObject::connect(ui->addServerTunnelPushButton, SIGNAL(released()), this, SLOT(addServerTunnelPushButtonReleased())); + QObject::connect(ui->addClientTunnelPushButton, SIGNAL(released()), this, SLOT(addClientTunnelPushButtonReleased())); + + +#ifndef ANDROID + QObject::connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); + + setIcon(); + trayIcon->show(); +#endif + + logViewerManagerPtr=new LogViewerManager(logStream_,ui->logViewerTextEdit,this); + assert(logViewerManagerPtr!=nullptr); + //onLoggingOptionsChange(); + //QMetaObject::connectSlotsByName(this); +} + +void MainWindow::logDestinationComboBoxValueChanged(const QString & text) { + bool fileEnabled = text==QString("file"); + uiSettings->logFileLineEdit->setEnabled(fileEnabled); + uiSettings->logFileBrowsePushButton->setEnabled(fileEnabled); +} + + +void MainWindow::updateRouterCommandsButtons() { + bool acceptsTunnels = i2p::context.AcceptsTunnels (); + routerCommandsUI->declineTransitTunnelsPushButton->setEnabled(acceptsTunnels); + routerCommandsUI->acceptTransitTunnelsPushButton->setEnabled(!acceptsTunnels); +} + +void MainWindow::showStatusPage(StatusPage newStatusPage){ + ui->stackedWidget->setCurrentIndex(0); + setStatusButtonsVisible(true); + statusPage=newStatusPage; + showHiddenInfoStatusMainPage=false; + if(newStatusPage!=StatusPage::commands){ + textBrowser->setHtml(getStatusPageHtml(false)); + textBrowser->show(); + routerCommandsParent->hide(); + pageWithBackButton->hide(); + }else{ + routerCommandsParent->show(); + textBrowser->hide(); + pageWithBackButton->hide(); + updateRouterCommandsButtons(); + } + wasSelectingAtStatusMainPage=false; +} + +void MainWindow::showAboutBox(const QString & href) { + AboutDialog dialog(this); + + /* + //doesn't work on older qt5: ‘class QStyleHints’ has no member named ‘showIsMaximized’ + if (!QGuiApplication::styleHints()->showIsFullScreen() && !QGuiApplication::styleHints()->showIsMaximized()) { + const QWindow * windowHandle = dialog.windowHandle(); + qDebug()<<"AboutDialog windowHandle ptr: "<<(size_t)windowHandle<screen():nullptr; //Qt 5.14+: dialog.screen() + qDebug()<<"AboutDialog screen ptr: "<<(size_t)screen<availableGeometry(); + //dialog.resize(availableGeometry.width() / 3, availableGeometry.height() * 2 / 3); + dialog.move((availableGeometry.width() - dialog.width()) / 2, + (availableGeometry.height() - dialog.height()) / 2); + } + } + */ + + (void) dialog.exec(); +} + +void MainWindow::showLogViewerPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);} +void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);} +void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);} +void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);} +void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(5);setStatusButtonsVisible(false);} + +void MainWindow::setStatusButtonsVisible(bool visible) { + ui->statusButtonsPane->setVisible(visible); +} + +// see also: HTTPServer.cpp +QString MainWindow::getStatusPageHtml(bool showHiddenInfo) { + std::stringstream s; + + s << ""; + + switch (statusPage) { + case main_page: + i2p::http::ShowStatus(s, showHiddenInfo, i2p::http::OutputFormatEnum::forQtUi); + break; + case commands: break; + case local_destinations: i2p::http::ShowLocalDestinations(s);break; + case leasesets: i2p::http::ShowLeasesSets(s); break; + case tunnels: i2p::http::ShowTunnels(s); break; + case transit_tunnels: i2p::http::ShowTransitTunnels(s); break; + case transports: i2p::http::ShowTransports(s); break; + case i2p_tunnels: i2p::http::ShowI2PTunnels(s); break; + case sam_sessions: i2p::http::ShowSAMSessions(s); break; + default: assert(false); break; + } + + std::string str = s.str(); + return QString::fromStdString(str); +} + +void MainWindow::showStatusMainPage() { showStatusPage(StatusPage::main_page); } +void MainWindow::showStatus_commands_Page() { showStatusPage(StatusPage::commands); } +void MainWindow::showStatus_local_destinations_Page() { showStatusPage(StatusPage::local_destinations); } +void MainWindow::showStatus_leasesets_Page() { showStatusPage(StatusPage::leasesets); } +void MainWindow::showStatus_tunnels_Page() { showStatusPage(StatusPage::tunnels); } +void MainWindow::showStatus_transit_tunnels_Page() { showStatusPage(StatusPage::transit_tunnels); } +void MainWindow::showStatus_transports_Page() { showStatusPage(StatusPage::transports); } +void MainWindow::showStatus_i2p_tunnels_Page() { showStatusPage(StatusPage::i2p_tunnels); } +void MainWindow::showStatus_sam_sessions_Page() { showStatusPage(StatusPage::sam_sessions); } + + +void MainWindow::scheduleStatusPageUpdates() { + statusPageUpdateTimer = new QTimer(this); + connect(statusPageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateStatusPage())); + statusPageUpdateTimer->start(10*1000/*millis*/); +} + +void MainWindow::statusHtmlPageMouseReleased() { + if(wasSelectingAtStatusMainPage){ + QString selection = textBrowser->textCursor().selectedText(); + if(!selection.isEmpty()&&!selection.isNull())return; + } + showHiddenInfoStatusMainPage=!showHiddenInfoStatusMainPage; + textBrowser->setHtml(getStatusPageHtml(showHiddenInfoStatusMainPage)); +} + +void MainWindow::statusHtmlPageSelectionChanged() { + wasSelectingAtStatusMainPage=true; +} + +void MainWindow::updateStatusPage() { + showHiddenInfoStatusMainPage=false; + textBrowser->setHtml(getStatusPageHtml(showHiddenInfoStatusMainPage)); +} + + +//TODO +void MainWindow::resizeEvent(QResizeEvent *event) +{ + QMainWindow::resizeEvent(event); + onResize(); +} + +//TODO +void MainWindow::onResize() +{ + if(isVisible()){ + ui->horizontalLayoutWidget->resize(ui->horizontalLayoutWidget->width(), height()); + + //status + ui->statusPage->resize(ui->statusPage->width(), height()); + + //tunnels + ui->tunnelsPage->resize(ui->tunnelsPage->width(), height()); + ui->verticalLayoutWidget_6->resize(ui->verticalLayoutWidget_6->width(), height()-20); + /*ui->tunnelsScrollArea->resize(ui->tunnelsScrollArea->width(), + ui->verticalLayoutWidget_6->height()-ui->label_5->height());*/ + } +} + +#ifndef ANDROID +void MainWindow::createActions() { + toggleWindowVisibleAction = new QAction(tr("&Toggle the window"), this); + connect(toggleWindowVisibleAction, SIGNAL(triggered()), this, SLOT(toggleVisibilitySlot())); + + //quitAction = new QAction(tr("&Quit"), this); + //connect(quitAction, SIGNAL(triggered()), QApplication::instance(), SLOT(quit())); +} + +void MainWindow::toggleVisibilitySlot() { + setVisible(!isVisible()); +} + +void MainWindow::createTrayIcon() { + trayIconMenu = new QMenu(this); + trayIconMenu->addAction(toggleWindowVisibleAction); + //trayIconMenu->addSeparator(); + //trayIconMenu->addAction(quitAction); + + trayIcon = new QSystemTrayIcon(this); + trayIcon->setContextMenu(trayIconMenu); +} + +void MainWindow::setIcon() { + QIcon icon(":icons/mask"); + trayIcon->setIcon(icon); + setWindowIcon(icon); + + trayIcon->setToolTip(QApplication::translate("MainWindow", "i2pd", 0)); +} + +void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { + switch (reason) { + case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::DoubleClick: + case QSystemTrayIcon::MiddleClick: + setVisible(!isVisible()); + break; + default: + qDebug() << "MainWindow::iconActivated(): unknown reason: " << reason << endl; + break; + } +} + +void MainWindow::closeEvent(QCloseEvent *event) { + if(quitting){ QMainWindow::closeEvent(event); return; } + if (trayIcon->isVisible()) { + QMessageBox::information(this, tr("i2pd"), + tr("The program will keep running in the " + "system tray. To gracefully terminate the program, " + "choose Graceful Quit at the main i2pd window.")); + hide(); + event->ignore(); + } +} +#endif + +void MainWindow::handleQuitButton() { + qDebug("Quit pressed. Hiding the main window"); +#ifndef ANDROID + quitting=true; +#endif + close(); + delayedSaveManagerPtr->appExiting(); + qDebug("Performing quit"); + QApplication::instance()->quit(); +} + +void MainWindow::handleGracefulQuitButton() { + qDebug("Graceful Quit pressed."); + ui->gracefulQuitPushButton->setText(QApplication::translate("MainWindow", "Graceful quit is in progress", 0)); + ui->gracefulQuitPushButton->setEnabled(false); + ui->gracefulQuitPushButton->adjustSize(); + ui->quitPage->adjustSize(); + i2p::context.SetAcceptsTunnels (false); // stop accpting tunnels + QTimer::singleShot(10*60*1000//millis + , this, SLOT(handleGracefulQuitTimerEvent())); +} + +void MainWindow::handleDoRestartButton() { + qDebug()<<"Do Restart pressed."; + emit i2pController->restartDaemon(); +} + + +void MainWindow::handleGracefulQuitTimerEvent() { + qDebug("Hiding the main window"); +#ifndef ANDROID + quitting=true; +#endif + close(); + delayedSaveManagerPtr->appExiting(); + qDebug("Performing quit"); + QApplication::instance()->quit(); +} + +MainWindow::~MainWindow() +{ + qDebug("Destroying main window"); + delete statusPageUpdateTimer; + delete delayedSaveManagerPtr; + delete saverPtr; + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + item->deleteLater(); + } + configItems.clear(); + //QMessageBox::information(0, "Debug", "mw destructor 1"); + //delete ui; + //QMessageBox::information(0, "Debug", "mw destructor 2"); +} + +FileChooserItem* MainWindow::initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile, bool readOnly){ + FileChooserItem* retVal; + retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton, this, requireExistingFile, readOnly); + MainWindowItem* super=retVal; + configItems.append(super); + return retVal; +} +void MainWindow::initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton){ + configItems.append(new FolderChooserItem(option, folderLineEdit, folderBrowsePushButton, this, true)); +} +/*void MainWindow::initCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new ComboBoxItem(option, comboBox)); + QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(saveAllConfigs())); +}*/ +void MainWindow::initLogDestinationCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new LogDestinationComboBoxItem(option, comboBox)); +} +void MainWindow::initLogLevelCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new LogLevelComboBoxItem(option, comboBox)); +} +void MainWindow::initSignatureTypeCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new SignatureTypeComboBoxItem(option, comboBox)); +} +void MainWindow::initIPAddressBox(ConfigOption option, QLineEdit* addressLineEdit, QString fieldNameTranslated){ + configItems.append(new IPAddressStringItem(option, addressLineEdit, fieldNameTranslated, this)); +} +void MainWindow::initTCPPortBox(ConfigOption option, QLineEdit* portLineEdit, QString fieldNameTranslated){ + configItems.append(new TCPPortStringItem(option, portLineEdit, fieldNameTranslated, this)); +} +void MainWindow::initCheckBox(ConfigOption option, QCheckBox* checkBox) { + configItems.append(new CheckBoxItem(option, checkBox)); +} +void MainWindow::initIntegerBox(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ + configItems.append(new IntegerStringItem(option, numberLineEdit, fieldNameTranslated, this)); +} +void MainWindow::initUInt32Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ + configItems.append(new UInt32StringItem(option, numberLineEdit, fieldNameTranslated, this)); +} +void MainWindow::initUInt16Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ + configItems.append(new UInt16StringItem(option, numberLineEdit, fieldNameTranslated, this)); +} +void MainWindow::initStringBox(ConfigOption option, QLineEdit* lineEdit){ + configItems.append(new BaseStringItem(option, lineEdit, QString(), this)); +} +NonGUIOptionItem* MainWindow::initNonGUIOption(ConfigOption option) { + NonGUIOptionItem * retValue; + configItems.append(retValue=new NonGUIOptionItem(option)); + return retValue; +} + +void MainWindow::loadAllConfigs(SaverImpl* saverPtr){ + + //BORROWED FROM ??? //TODO move this code into single location + std::string config; i2p::config::GetOption("conf", config); + std::string datadir; i2p::config::GetOption("datadir", datadir); + bool service = false; +#ifndef _WIN32 + i2p::config::GetOption("service", service); +#endif + i2p::fs::DetectDataDir(datadir, service); + i2p::fs::Init(); + + datadir = i2p::fs::GetDataDir(); + // TODO: drop old name detection in v2.8.0 + if (config == "") + { + config = i2p::fs::DataDirPath("i2p.conf"); + if (i2p::fs::Exists (config)) { + LogPrint(eLogWarning, "Daemon: please rename i2p.conf to i2pd.conf here: ", config); + } else { + config = i2p::fs::DataDirPath("i2pd.conf"); + /*if (!i2p::fs::Exists (config)) {}*/ + } + } + + //BORROWED FROM ClientContext.cpp //TODO move this code into single location + std::string tunConf; i2p::config::GetOption("tunconf", tunConf); + if (tunConf == "") { + // TODO: cleanup this in 2.8.0 + tunConf = i2p::fs::DataDirPath ("tunnels.cfg"); + if (i2p::fs::Exists(tunConf)) { + LogPrint(eLogWarning, "FS: please rename tunnels.cfg -> tunnels.conf here: ", tunConf); + } else { + tunConf = i2p::fs::DataDirPath ("tunnels.conf"); + } + } + + this->confpath = config.c_str(); + this->datadir = datadir.c_str(); + this->tunconfpath = tunConf.c_str(); + + saverPtr->setConfPath(this->confpath); + saverPtr->setTunnelsConfPath(this->tunconfpath); + + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + item->loadFromConfigOption(); + } + + ReadTunnelsConfig(); + + //onLoggingOptionsChange(); +} + +void MainWindow::layoutTunnels() { + + int height=0; + ui->tunnelsScrollAreaWidgetContents->setGeometry(0,0,0,0); + for(std::map::iterator it = tunnelConfigs.begin(); it != tunnelConfigs.end(); ++it) { + //const std::string& name=it->first; + TunnelConfig* tunconf = it->second; + TunnelPane * tunnelPane=tunconf->getTunnelPane(); + if(!tunnelPane)continue; + int h=tunnelPane->height(); + height+=h; + //qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + //int h=tunnelPane->appendClientTunnelForm(ctc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); + } + //qDebug() << "tun.setting height:" << height; + ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, height)); + /*QList childWidgets = ui->tunnelsScrollAreaWidgetContents->findChildren(); + foreach(QWidget* widget, childWidgets) + widget->show();*/ +} + +void MainWindow::deleteTunnelFromUI(std::string tunnelName, TunnelConfig* cnf) { + TunnelPane* tp = cnf->getTunnelPane(); + if(!tp)return; + tunnelPanes.remove(tp); + tp->deleteWidget(); + layoutTunnels(); +} + +/** returns false iff not valid items present and save was aborted */ +bool MainWindow::saveAllConfigs(bool reloadAfterSave, FocusEnum focusOn, std::string tunnelNameToFocus, QWidget* widgetToFocus){ + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); + programOptionsWriterCurrentSection=""; + /*if(!logFileNameOption->lineEdit->text().trimmed().isEmpty())logOption->optionValue=boost::any(std::string("file")); + else logOption->optionValue=boost::any(std::string("stdout"));*/ + daemonOption->optionValue=boost::any(false); + serviceOption->optionValue=boost::any(false); + + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + bool alreadyDisplayedIfWrong=false; + if(!item->isValid(alreadyDisplayedIfWrong)){ + if(!alreadyDisplayedIfWrong) + highlightWrongInput( + QApplication::tr("Invalid value for")+" "+item->getConfigOption().section+"::"+item->getConfigOption().option+". "+item->getRequirementToBeValid()+" "+cannotSaveSettings, + WrongInputPageEnum::generalSettingsPage, + item->getWidgetToFocus()); + return false; + } + } + delayedSaveManagerPtr->delayedSave(reloadAfterSave, ++dataSerial, focusOn, tunnelNameToFocus, widgetToFocus);//TODO does dataSerial work? //FIXME + + //onLoggingOptionsChange(); + return true; +} + +void FileChooserItem::pushButtonReleased() { + QString fileName = lineEdit->text().trimmed(); + fileName = requireExistingFile ? + QFileDialog::getOpenFileName(nullptr, tr("Open File"), fileName, tr("All Files (*.*)")) : + QFileDialog::getSaveFileName(nullptr, tr("Open File"), fileName, tr("All Files (*.*)")); + if(fileName.length()>0)lineEdit->setText(fileName); +} +void FolderChooserItem::pushButtonReleased() { + QString fileName = lineEdit->text().trimmed(); + assert(requireExistingFile); + fileName = QFileDialog::getExistingDirectory(nullptr, tr("Open Folder"), fileName); + if(fileName.length()>0)lineEdit->setText(fileName); +} + +void BaseStringItem::installListeners(MainWindow *mainWindow) { + QObject::connect(lineEdit, SIGNAL(textChanged(const QString &)), mainWindow, SLOT(updated())); +} +bool BaseStringItem::isValid(bool & alreadyDisplayedIfWrong) { + alreadyDisplayedIfWrong=true; + return ::isValidSingleLine(lineEdit, WrongInputPageEnum::generalSettingsPage, mainWindow); +} + +void ComboBoxItem::installListeners(MainWindow *mainWindow) { + QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), mainWindow, SLOT(updated())); +} +void CheckBoxItem::installListeners(MainWindow *mainWindow) { + QObject::connect(checkBox, SIGNAL(stateChanged(int)), mainWindow, SLOT(updated())); +} + +void MainWindow::updated() { + ui->wrongInputLabel->setVisible(false); + adjustSizesAccordingToWrongLabel(); + + bool correct = applyTunnelsUiToConfigs(); + if(!correct) return; + saveAllConfigs(false, FocusEnum::noFocus); +} + +void MainWindowItem::installListeners(MainWindow *mainWindow) {} + +void MainWindow::appendTunnelForms(std::string tunnelNameToFocus) { + int height=0; + ui->tunnelsScrollAreaWidgetContents->setGeometry(0,0,0,0); + for(std::map::iterator it = tunnelConfigs.begin(); it != tunnelConfigs.end(); ++it) { + const std::string& name=it->first; + TunnelConfig* tunconf = it->second; + ServerTunnelConfig* stc = tunconf->asServerTunnelConfig(); + if(stc){ + ServerTunnelPane * tunnelPane=new ServerTunnelPane(&tunnelsPageUpdateListener, stc, ui->wrongInputLabel, ui->wrongInputLabel, this); + tunconf->setTunnelPane(tunnelPane); + int h=tunnelPane->appendServerTunnelForm(stc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); + height+=h; + //qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + tunnelPanes.push_back(tunnelPane); + if(name==tunnelNameToFocus){ + tunnelPane->getNameLineEdit()->setFocus(); + ui->tunnelsScrollArea->ensureWidgetVisible(tunnelPane->getNameLineEdit()); + } + continue; + } + ClientTunnelConfig* ctc = tunconf->asClientTunnelConfig(); + if(ctc){ + ClientTunnelPane * tunnelPane=new ClientTunnelPane(&tunnelsPageUpdateListener, ctc, ui->wrongInputLabel, ui->wrongInputLabel, this); + tunconf->setTunnelPane(tunnelPane); + int h=tunnelPane->appendClientTunnelForm(ctc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); + height+=h; + //qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + tunnelPanes.push_back(tunnelPane); + if(name==tunnelNameToFocus){ + tunnelPane->getNameLineEdit()->setFocus(); + ui->tunnelsScrollArea->ensureWidgetVisible(tunnelPane->getNameLineEdit()); + } + continue; + } + throw "unknown TunnelConfig subtype"; + } + //qDebug() << "tun.setting height:" << height; + ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, height)); + QList childWidgets = ui->tunnelsScrollAreaWidgetContents->findChildren(); + foreach(QWidget* widget, childWidgets) + widget->show(); +} +void MainWindow::deleteTunnelForms() { + for(std::list::iterator it = tunnelPanes.begin(); it != tunnelPanes.end(); ++it) { + TunnelPane* tp = *it; + ServerTunnelPane* stp = tp->asServerTunnelPane(); + if(stp){ + stp->deleteServerTunnelForm(); + delete stp; + continue; + } + ClientTunnelPane* ctp = tp->asClientTunnelPane(); + if(ctp){ + ctp->deleteClientTunnelForm(); + delete ctp; + continue; + } + throw "unknown TunnelPane subtype"; + } + tunnelPanes.clear(); +} + +bool MainWindow::applyTunnelsUiToConfigs() { + for(std::list::iterator it = tunnelPanes.begin(); it != tunnelPanes.end(); ++it) { + TunnelPane* tp = *it; + if(!tp->applyDataFromUIToTunnelConfig())return false; + } + return true; +} + +void MainWindow::reloadTunnelsConfigAndUI_QString(QString tunnelNameToFocus) { + reloadTunnelsConfigAndUI(tunnelNameToFocus.toStdString(), nullptr); +} + +void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus, QWidget* widgetToFocus) { + deleteTunnelForms(); + for (std::map::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) { + TunnelConfig* tunconf = it->second; + delete tunconf; + } + tunnelConfigs.clear(); + ReadTunnelsConfig(); + appendTunnelForms(tunnelNameToFocus); +} + +void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::updated(std::string oldName, TunnelConfig* tunConf) { + if(oldName!=tunConf->getName()) { + //name has changed + std::map::const_iterator it=mainWindow->tunnelConfigs.find(oldName); + if(it!=mainWindow->tunnelConfigs.end())mainWindow->tunnelConfigs.erase(it); + mainWindow->tunnelConfigs[tunConf->getName()]=tunConf; + mainWindow->saveAllConfigs(true, FocusEnum::focusOnTunnelName, tunConf->getName()); + } + else + mainWindow->saveAllConfigs(false, FocusEnum::noFocus); +} + +void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::needsDeleting(std::string oldName){ + mainWindow->DeleteTunnelNamed(oldName); +} + +void MainWindow::addServerTunnelPushButtonReleased() { + CreateDefaultServerTunnel(); +} + +void MainWindow::addClientTunnelPushButtonReleased() { + CreateDefaultClientTunnel(); +} + +void MainWindow::setI2PController(i2p::qt::Controller* controller_) { + this->i2pController = controller_; +} + +void MainWindow::runPeerTest() { + i2p::transport::transports.PeerTest(); +} + +void MainWindow::enableTransit() { + i2p::context.SetAcceptsTunnels(true); + updateRouterCommandsButtons(); +} + +void MainWindow::disableTransit() { + i2p::context.SetAcceptsTunnels(false); + updateRouterCommandsButtons(); +} + +void MainWindow::anchorClickedHandler(const QUrl & link) { + QString debugStr=QString()+"anchorClicked: "+"\""+link.toString()+"\""; + qDebug()< params; + i2p::http::URL url; + url.parse(str.toStdString()); + url.parse_query(params); + const std::string page = params["page"]; + const std::string cmd = params["cmd"]; + if (page == "sam_session") { + pageWithBackButton->show(); + textBrowser->hide(); + std::stringstream s; + i2p::http::ShowSAMSession (s, params["sam_id"]); + childTextBrowser->setHtml(QString::fromStdString(s.str())); + } else if (page == "local_destination") { + std::string b32 = params["b32"]; + currentLocalDestinationB32 = b32; + pageWithBackButton->show(); + textBrowser->hide(); + std::stringstream s; + std::string strstd = currentLocalDestinationB32; + i2p::http::ShowLocalDestination(s,strstd,0); + childTextBrowser->setHtml(QString::fromStdString(s.str())); + } else if (page == "i2cp_local_destination") { + pageWithBackButton->show(); + textBrowser->hide(); + std::stringstream s; + i2p::http::ShowI2CPLocalDestination (s, params["i2cp_id"]); + childTextBrowser->setHtml(QString::fromStdString(s.str())); + } else if(cmd == "closestream") { + std::string b32 = params["b32"]; + uint32_t streamID = std::stoul(params["streamID"], nullptr); + + i2p::data::IdentHash ident; + ident.FromBase32 (b32); + auto dest = i2p::client::context.FindLocalDestination (ident); + + if (streamID) { + if (dest) { + if(dest->DeleteStream (streamID)) + QMessageBox::information( + this, + QApplication::tr("Success"), + QApplication::tr("SUCCESS: Stream closed")); + else + QMessageBox::critical( + this, + QApplication::tr("Error"), + QApplication::tr("ERROR: Stream not found or already was closed")); + } + else + QMessageBox::critical( + this, + QApplication::tr("Error"), + QApplication::tr("ERROR: Destination not found")); + } + else + QMessageBox::critical( + this, + QApplication::tr("Error"), + QApplication::tr("ERROR: StreamID is null")); + std::stringstream s; + std::string strstd = currentLocalDestinationB32; + i2p::http::ShowLocalDestination(s,strstd,0); + childTextBrowser->setHtml(QString::fromStdString(s.str())); + } +} + +void MainWindow::backClickedFromChild() { + showStatusPage(statusPage); +} + +void MainWindow::adjustSizesAccordingToWrongLabel() { + constexpr auto HEIGHT = 581; + constexpr auto WIDTH = 707; + if(ui->wrongInputLabel->isVisible()) { + int dh = ui->wrongInputLabel->height()+ui->verticalLayout_7->layout()->spacing(); + ui->verticalLayout_7->invalidate(); + ui->wrongInputLabel->adjustSize(); + ui->stackedWidget->adjustSize(); + const auto height = HEIGHT - dh; + ui->stackedWidget->setFixedHeight(height); + ui->settingsPage->setFixedHeight(height); + ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, WIDTH, height)); + ui->stackedWidget->setFixedHeight(height); + ui->settingsScrollArea->setFixedHeight(height-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); + ui->settingsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + ui->tunnelsScrollArea->setFixedHeight(height-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); + ui->tunnelsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + }else{ + ui->verticalLayout_7->invalidate(); + ui->wrongInputLabel->adjustSize(); + ui->stackedWidget->adjustSize(); + ui->stackedWidget->setFixedHeight(HEIGHT); + ui->settingsPage->setFixedHeight(HEIGHT); + ui->verticalLayoutWidget_4->setGeometry(QRect(0, 0, WIDTH, HEIGHT)); + ui->stackedWidget->setFixedHeight(HEIGHT); + ui->settingsScrollArea->setFixedHeight(HEIGHT-settingsTitleLabelNominalHeight-ui->verticalLayout_4->spacing()); + ui->settingsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + ui->tunnelsScrollArea->setFixedHeight(HEIGHT-settingsTitleLabelNominalHeight-ui->horizontalLayout_42->geometry().height()-2*ui->verticalLayout_4->spacing()); + ui->tunnelsTitleLabel->setFixedHeight(settingsTitleLabelNominalHeight); + } +} + +void MainWindow::highlightWrongInput(QString warningText, WrongInputPageEnum inputPage, QWidget* widgetToFocus) { + bool redVisible = ui->wrongInputLabel->isVisible(); + ui->wrongInputLabel->setVisible(true); + ui->wrongInputLabel->setText(warningText); + if(!redVisible)adjustSizesAccordingToWrongLabel(); + if(widgetToFocus){ui->settingsScrollArea->ensureWidgetVisible(widgetToFocus);widgetToFocus->setFocus();} + switch(inputPage) { + case WrongInputPageEnum::generalSettingsPage: showSettingsPage(); break; + case WrongInputPageEnum::tunnelsSettingsPage: showTunnelsPage(); break; + default: assert(false); break; + } +} + +void MainWindow::syncLogLevel (int /*comboBoxIndex*/) { + std::string level = uiSettings->logLevelComboBox->currentText().toLower().toStdString(); + if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug") + i2p::log::Logger().SetLogLevel(level); + else { + LogPrint(eLogError, "unknown loglevel set attempted"); + return; + } + i2p::log::Logger().Reopen (); +} + diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..e1ddcc6 --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,883 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QVBoxLayout" +#include "QUrl" + +#ifndef ANDROID +# include +# include +# include +#endif + +#include + +#include + +#include "MainWindowItems.h" +#include "TunnelPane.h" +#include "ServerTunnelPane.h" +#include "ClientTunnelPane.h" +#include "TunnelConfig.h" +#include "textbrowsertweaked1.h" + +#include "Config.h" +#include "FS.h" + +#include + +#include +#include + +#include "TunnelsPageUpdateListener.h" + +#include "DaemonQT.h" +#include "SignatureTypeComboboxFactory.h" +#include "pagewithbackbutton.h" + +#include + +#include "widgetlockregistry.h" +#include "widgetlock.h" + +#include "DelayedSaveManager.h" +#include "DelayedSaveManagerImpl.h" +#include "SaverImpl.h" + +#include "I2pdQtUtil.h" + +class SaverImpl; + +class LogViewerManager; + +template +bool isType(boost::any& a) { + return +#ifdef BOOST_AUX_ANY_TYPE_ID_NAME + std::strcmp(a.type().name(), typeid(ValueType).name()) == 0 +#else + a.type() == typeid(ValueType) +#endif + ; +} + +class ConfigOption { +public: + QString section; + QString option; + //MainWindow::DefaultValueGetter defaultValueGetter; + ConfigOption(QString section_, QString option_/*, DefaultValueGetter defaultValueGetter_*/): + section(section_) + , option(option_) + //, defaultValueGetter(defaultValueGetter_) + {} + +}; + +extern std::string programOptionsWriterCurrentSection; + +class MainWindow; + +class MainWindowItem : public QObject { + Q_OBJECT +private: + ConfigOption option; + QWidget* widgetToFocus; + QString requirementToBeValid; + const bool readOnly; +public: + MainWindowItem(ConfigOption option_, QWidget* widgetToFocus_, QString requirementToBeValid_, bool readOnly_=false) : + option(option_), widgetToFocus(widgetToFocus_), requirementToBeValid(requirementToBeValid_), readOnly(readOnly_) {} + QWidget* getWidgetToFocus(){return widgetToFocus;} + QString& getRequirementToBeValid() { return requirementToBeValid; } + ConfigOption& getConfigOption() { return option; } + boost::any optionValue; + virtual ~MainWindowItem(){} + virtual void installListeners(MainWindow *mainWindow); + virtual void loadFromConfigOption(){ + std::string optName=""; + if(!option.section.isEmpty())optName=option.section.toStdString()+std::string("."); + optName+=option.option.toStdString(); + //qDebug() << "loadFromConfigOption[" << optName.c_str() << "]"; + boost::any programOption; + i2p::config::GetOptionAsAny(optName, programOption); + optionValue=programOption.empty()?boost::any(std::string("")) + :boost::any_cast(programOption).value(); + } + virtual void saveToStringStream(std::stringstream& out){ + if(readOnly)return; //should readOnly items (conf=) error somewhere, instead of silently skipping save? + if(isType(optionValue)) { + std::string v = boost::any_cast(optionValue); + if(v.empty())return; + } + if(optionValue.empty())return; + std::string rtti = optionValue.type().name(); + std::string optName=""; + if(!option.section.isEmpty())optName=option.section.toStdString()+std::string("."); + optName+=option.option.toStdString(); + //qDebug() << "Writing option" << optName.c_str() << "of type" << rtti.c_str(); + std::string sectionAsStdStr = option.section.toStdString(); + if(!option.section.isEmpty() && + sectionAsStdStr!=programOptionsWriterCurrentSection) { + out << "[" << sectionAsStdStr << "]\n"; + programOptionsWriterCurrentSection=sectionAsStdStr; + } + out << option.option.toStdString() << "="; + if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << (boost::any_cast(optionValue) ? "true" : "false"); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else out << boost::any_cast(optionValue); //let it throw + out << "\n\n"; + } + virtual bool isValid(bool & alreadyDisplayedIfWrong){alreadyDisplayedIfWrong=false;return true;} +}; +class NonGUIOptionItem : public MainWindowItem { +public: + NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_, nullptr, QString()) {} + virtual ~NonGUIOptionItem(){} + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } +}; +class BaseStringItem : public MainWindowItem { + Q_OBJECT +public: + QLineEdit* lineEdit; + MainWindow *mainWindow; + BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_, MainWindow* mainWindow_, bool readOnly=false): + MainWindowItem(option_, lineEdit_, requirementToBeValid_, readOnly), + lineEdit(lineEdit_), + mainWindow(mainWindow_) + {}; + virtual ~BaseStringItem(){} + virtual void installListeners(MainWindow *mainWindow); + virtual QString toString(){ + return boost::any_cast(optionValue).c_str(); + } + virtual boost::any fromString(QString s){return boost::any(s.toStdString());} + virtual void loadFromConfigOption(){ + MainWindowItem::loadFromConfigOption(); + lineEdit->setText(toString()); + } + + virtual void saveToStringStream(std::stringstream& out){ + optionValue=fromString(lineEdit->text()); + MainWindowItem::saveToStringStream(out); + } + virtual bool isValid(bool & alreadyDisplayedIfWrong); +}; +class FileOrFolderChooserItem : public BaseStringItem { +protected: + const bool requireExistingFile; +public: + QPushButton* browsePushButton; + FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile_, bool readOnly) : + BaseStringItem(option_, lineEdit_, QString(), mw, readOnly), requireExistingFile(requireExistingFile_), browsePushButton(browsePushButton_) {} + virtual ~FileOrFolderChooserItem(){} +}; +class FileChooserItem : public FileOrFolderChooserItem { + Q_OBJECT +private slots: + void pushButtonReleased(); +public: + FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile, bool readOnly) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFile, readOnly) { + QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); + } +}; +class FolderChooserItem : public FileOrFolderChooserItem{ + Q_OBJECT +private slots: + void pushButtonReleased(); +public: + FolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFolder) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFolder, false) { + QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); + } +}; +class ComboBoxItem : public MainWindowItem { +public: + QComboBox* comboBox; + ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_,comboBox_,QString()), comboBox(comboBox_){} + virtual ~ComboBoxItem(){} + virtual void installListeners(MainWindow *mainWindow); + virtual void loadFromConfigOption()=0; + virtual void saveToStringStream(std::stringstream& out)=0; + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return ; } +}; +class LogDestinationComboBoxItem : public ComboBoxItem { +public: + LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : + ComboBoxItem(option_, comboBox_) {} + virtual ~LogDestinationComboBoxItem(){} + virtual void loadFromConfigOption(){ + MainWindowItem::loadFromConfigOption(); + const char * ld = boost::any_cast(optionValue).c_str(); + comboBox->setCurrentText(QString(ld)); + } + virtual void saveToStringStream(std::stringstream& out){ + std::string logDest = comboBox->currentText().toStdString(); + optionValue=logDest; + MainWindowItem::saveToStringStream(out); + } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } + + Q_OBJECT +}; +class LogLevelComboBoxItem : public ComboBoxItem { +public: + LogLevelComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {} + virtual ~LogLevelComboBoxItem(){} + virtual void loadFromConfigOption(){ + MainWindowItem::loadFromConfigOption(); + const char * ll = boost::any_cast(optionValue).c_str(); + comboBox->setCurrentText(QString(ll)); + } + virtual void saveToStringStream(std::stringstream& out){ + optionValue=comboBox->currentText().toStdString(); + MainWindowItem::saveToStringStream(out); + } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } +}; +class SignatureTypeComboBoxItem : public ComboBoxItem { +public: + SignatureTypeComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {} + virtual ~SignatureTypeComboBoxItem(){} + virtual void loadFromConfigOption(){ + MainWindowItem::loadFromConfigOption(); + while(comboBox->count()>0)comboBox->removeItem(0); + uint16_t selected = (uint16_t) boost::any_cast(optionValue); + SignatureTypeComboBoxFactory::fillComboBox(comboBox, selected); + } + virtual void saveToStringStream(std::stringstream& out){ + uint16_t selected = SignatureTypeComboBoxFactory::getSigType(comboBox->currentData()); + optionValue=(unsigned short)selected; + MainWindowItem::saveToStringStream(out); + } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } +}; +class CheckBoxItem : public MainWindowItem { +public: + QCheckBox* checkBox; + CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_,checkBox_,QString()), checkBox(checkBox_){} + virtual ~CheckBoxItem(){} + virtual void installListeners(MainWindow *mainWindow); + virtual void loadFromConfigOption(){ + MainWindowItem::loadFromConfigOption(); + //qDebug() << "setting value for checkbox " << checkBox->text(); + checkBox->setChecked(boost::any_cast(optionValue)); + } + virtual void saveToStringStream(std::stringstream& out){ + optionValue=checkBox->isChecked(); + MainWindowItem::saveToStringStream(out); + } + //virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; } +}; +class BaseFormattedStringItem : public BaseStringItem { +public: + QString fieldNameTranslated; + BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, QString requirementToBeValid_, MainWindow* mw) : + BaseStringItem(option_, lineEdit_, requirementToBeValid_, mw), fieldNameTranslated(fieldNameTranslated_) {} + virtual ~BaseFormattedStringItem(){} + //virtual bool isValid(bool & alreadyDisplayedIfWrong)=0; +}; +class IntegerStringItem : public BaseFormattedStringItem { +public: + IntegerStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be a valid integer."), mw) {} + virtual ~IntegerStringItem(){} + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; + auto str=lineEdit->text(); + bool ok; + str.toInt(&ok); + return ok; + } + virtual QString toString(){return QString::number(boost::any_cast(optionValue));} + virtual boost::any fromString(QString s){return boost::any(std::stoi(s.toStdString()));} +}; +class UShortStringItem : public BaseFormattedStringItem { +public: + UShortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned short integer."), mw) {} + virtual ~UShortStringItem(){} + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; + auto str=lineEdit->text(); + bool ok; + str.toUShort(&ok); + return ok; + } + virtual QString toString(){return QString::number(boost::any_cast(optionValue));} + virtual boost::any fromString(QString s){return boost::any((unsigned short)std::stoi(s.toStdString()));} +}; +class UInt32StringItem : public BaseFormattedStringItem { +public: + UInt32StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 32-bit integer."), mw) {} + virtual ~UInt32StringItem(){} + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; + auto str=lineEdit->text(); + bool ok; + str.toUInt(&ok); + return ok; + } + virtual QString toString(){return QString::number(boost::any_cast(optionValue));} + virtual boost::any fromString(QString s){return boost::any((uint32_t)std::stoi(s.toStdString()));} +}; +class UInt16StringItem : public BaseFormattedStringItem { +public: + UInt16StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 16-bit integer."), mw) {} + virtual ~UInt16StringItem(){} + virtual bool isValid(bool & alreadyDisplayedIfWrong){ + bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong); + if(!correct)return false; + alreadyDisplayedIfWrong = false; + auto str=lineEdit->text(); + bool ok; + str.toUShort(&ok); + return ok; + } + virtual QString toString(){return QString::number(boost::any_cast(optionValue));} + virtual boost::any fromString(QString s){return boost::any((uint16_t)std::stoi(s.toStdString()));} +}; +class IPAddressStringItem : public BaseFormattedStringItem { +public: + IPAddressStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be an IPv4 address"), mw) {} + //virtual bool isValid(bool & alreadyDisplayedIfWrong){return true;}//todo +}; +class TCPPortStringItem : public UShortStringItem { +public: + TCPPortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) : + UShortStringItem(option_, lineEdit_, fieldNameTranslated_,mw) {} +}; + +namespace Ui { + class MainWindow; + class StatusButtonsForm; + class routerCommandsWidget; + class GeneralSettingsContentsForm; +} + +using namespace i2p::client; + +class TunnelPane; + +using namespace i2p::qt; + +class Controller; + +class DelayedSaveManagerImpl; + +class MainWindow : public QMainWindow { + Q_OBJECT +private: + std::string currentLocalDestinationB32; + std::shared_ptr logStream; + DelayedSaveManagerImpl* delayedSaveManagerPtr; + DelayedSaveManager::DATA_SERIAL_TYPE dataSerial; +public: + explicit MainWindow(std::shared_ptr logStream_, QWidget *parent=nullptr); + ~MainWindow(); + + void setI2PController(i2p::qt::Controller* controller_); + + void highlightWrongInput(QString warningText, WrongInputPageEnum inputPage, QWidget* widgetToFocus); + + //typedef std::function DefaultValueGetter; + +//#ifndef ANDROID +// void setVisible(bool visible); +//#endif + +private: + enum StatusPage {main_page, commands, local_destinations, leasesets, tunnels, transit_tunnels, + transports, i2p_tunnels, sam_sessions}; +private slots: + void updated(); + + void handleQuitButton(); + void handleGracefulQuitButton(); + void handleDoRestartButton(); + void handleGracefulQuitTimerEvent(); +#ifndef ANDROID + void setIcon(); + void iconActivated(QSystemTrayIcon::ActivationReason reason); + void toggleVisibilitySlot(); +#endif + void scheduleStatusPageUpdates(); + void statusHtmlPageMouseReleased(); + void statusHtmlPageSelectionChanged(); + void updateStatusPage(); + + void showStatusMainPage(); + void showStatus_commands_Page(); + void runPeerTest(); + void enableTransit(); + void disableTransit(); + +public slots: + void syncLogLevel (int comboBoxIndex); + + void showStatus_local_destinations_Page(); + void showStatus_leasesets_Page(); + void showStatus_tunnels_Page(); + void showStatus_transit_tunnels_Page(); + void showStatus_transports_Page(); + void showStatus_i2p_tunnels_Page(); + void showStatus_sam_sessions_Page(); + + void showLogViewerPage(); + void showSettingsPage(); + void showTunnelsPage(); + void showRestartPage(); + void showQuitPage(); + void showAboutBox(const QString & href); + +private: + StatusPage statusPage; + QTimer * statusPageUpdateTimer; + bool wasSelectingAtStatusMainPage; + bool showHiddenInfoStatusMainPage; + + LogViewerManager *logViewerManagerPtr; + + void showStatusPage(StatusPage newStatusPage); +#ifndef ANDROID + void createActions(); + void createTrayIcon(); + bool quitting; + QAction *toggleWindowVisibleAction; + QSystemTrayIcon *trayIcon; + QMenu *trayIconMenu; +#endif + +public: + Ui::MainWindow* ui; + Ui::StatusButtonsForm* statusButtonsUI; + Ui::routerCommandsWidget* routerCommandsUI; + Ui::GeneralSettingsContentsForm* uiSettings; + void adjustSizesAccordingToWrongLabel(); + bool applyTunnelsUiToConfigs(); +private: + int settingsTitleLabelNominalHeight; + TextBrowserTweaked1 * textBrowser; + QWidget * routerCommandsParent; + PageWithBackButton * pageWithBackButton; + TextBrowserTweaked1 * childTextBrowser; + + widgetlockregistry widgetlocks; + + i2p::qt::Controller* i2pController; + +protected: + + void updateRouterCommandsButtons(); + +#ifndef ANDROID + void closeEvent(QCloseEvent *event); +#endif + void resizeEvent(QResizeEvent* event); + void onResize(); + + void setStatusButtonsVisible(bool visible); + + QString getStatusPageHtml(bool showHiddenInfo); + + QList configItems; + NonGUIOptionItem* daemonOption; + NonGUIOptionItem* serviceOption; + //LogDestinationComboBoxItem* logOption; + FileChooserItem* logFileNameOption; + + FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile, bool readOnly=false); + void initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton); + //void initCombobox(ConfigOption option, QComboBox* comboBox); + void initLogDestinationCombobox(ConfigOption option, QComboBox* comboBox); + void initLogLevelCombobox(ConfigOption option, QComboBox* comboBox); + void initSignatureTypeCombobox(ConfigOption option, QComboBox* comboBox); + void initIPAddressBox(ConfigOption option, QLineEdit* addressLineEdit, QString fieldNameTranslated); + void initTCPPortBox(ConfigOption option, QLineEdit* portLineEdit, QString fieldNameTranslated); + void initCheckBox(ConfigOption option, QCheckBox* checkBox); + void initIntegerBox(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated); + void initUInt32Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated); + void initUInt16Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated); + void initStringBox(ConfigOption option, QLineEdit* lineEdit); + NonGUIOptionItem* initNonGUIOption(ConfigOption option); + + void loadAllConfigs(SaverImpl* saverPtr); + void layoutTunnels(); + +public slots: + /** returns false iff not valid items present and save was aborted */ + bool saveAllConfigs(bool reloadAfterSave, FocusEnum focusOn, std::string tunnelNameToFocus="", QWidget* widgetToFocus=nullptr); + void reloadTunnelsConfigAndUI(std::string tunnelNameToFocus, QWidget* widgetToFocus); + void reloadTunnelsConfigAndUI() { reloadTunnelsConfigAndUI("", nullptr); } + + //focus none + void reloadTunnelsConfigAndUI_QString(QString tunnelNameToFocus); + void addServerTunnelPushButtonReleased(); + void addClientTunnelPushButtonReleased(); + + void anchorClickedHandler(const QUrl & link); + void backClickedFromChild(); + + void logDestinationComboBoxValueChanged(const QString & text); + +private: + QString datadir; + QString confpath; + QString tunconfpath; + + std::map tunnelConfigs; + std::list tunnelPanes; + + void appendTunnelForms(std::string tunnelNameToFocus); + void deleteTunnelForms(); + void deleteTunnelFromUI(std::string tunnelName, TunnelConfig* cnf); + + template + std::string GetI2CPOption (const Section& section, const std::string& name, const std::string& value) const + { + return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value); + } + + template + std::string GetI2CPOption (const Section& section, const std::string& name, const char* value) const + { + return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::string (value)); + } + + template + std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const + { + return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value)); + } + + template + void ReadI2CPOptions (const Section& section, std::map& options, I2CPParameters& param + /*TODO fill param*/) const + { + std::string _INBOUND_TUNNEL_LENGTH = options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNEL_LENGTH, DEFAULT_INBOUND_TUNNEL_LENGTH); + param.setInbound_length(QString(_INBOUND_TUNNEL_LENGTH.c_str())); + std::string _OUTBOUND_TUNNEL_LENGTH = options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH); + param.setOutbound_length(QString(_OUTBOUND_TUNNEL_LENGTH.c_str())); + std::string _INBOUND_TUNNELS_QUANTITY = options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY); + param.setInbound_quantity( QString(_INBOUND_TUNNELS_QUANTITY.c_str())); + std::string _OUTBOUND_TUNNELS_QUANTITY = options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY); + param.setOutbound_quantity(QString(_OUTBOUND_TUNNELS_QUANTITY.c_str())); + std::string _TAGS_TO_SEND = options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND); + param.setCrypto_tagsToSend(QString(_TAGS_TO_SEND.c_str())); + std::string _i2cp_leaseSetAuthType = options[I2CP_PARAM_LEASESET_AUTH_TYPE] = GetI2CPOption (section, I2CP_PARAM_LEASESET_AUTH_TYPE, 0); + param.set_i2cp_leaseSetAuthType(QString(_i2cp_leaseSetAuthType.c_str())); + const char DEFAULT_LEASESET_ENCRYPTION_TYPE[] = ""; + std::string _i2cp_leaseSetEncType = options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = GetI2CPOption (section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, DEFAULT_LEASESET_ENCRYPTION_TYPE);//todo Identity's type by default + param.set_i2cp_leaseSetEncType(QString(_i2cp_leaseSetEncType.c_str())); + std::string _i2cp_leaseSetPrivKey = options[I2CP_PARAM_LEASESET_PRIV_KEY] = GetI2CPOption (section, I2CP_PARAM_LEASESET_PRIV_KEY, ""); + param.set_i2cp_leaseSetPrivKey(QString(_i2cp_leaseSetPrivKey.c_str())); + std::string _i2cp_leaseSetType = options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption (section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE); + param.set_i2cp_leaseSetType(QString(_i2cp_leaseSetType.c_str())); + std::string _i2p_streaming_answerPings= options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption (section, I2CP_PARAM_STREAMING_ANSWER_PINGS, DEFAULT_ANSWER_PINGS); + param.set_i2p_streaming_answerPings((_i2p_streaming_answerPings.compare("true")==0)||(_i2p_streaming_answerPings.compare("yes")==0)); + std::string _i2p_streaming_initialAckDelay = options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption (section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY); + param.set_i2p_streaming_initialAckDelay(QString(_i2p_streaming_initialAckDelay.c_str())); + options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);//TODO include into param + options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);//TODO include into param + } + + void CreateDefaultI2CPOptions (I2CPParameters& param + /*TODO fill param*/) const + { + const int _INBOUND_TUNNEL_LENGTH = DEFAULT_INBOUND_TUNNEL_LENGTH; + param.setInbound_length(QString::number(_INBOUND_TUNNEL_LENGTH)); + const int _OUTBOUND_TUNNEL_LENGTH = DEFAULT_OUTBOUND_TUNNEL_LENGTH; + param.setOutbound_length(QString::number(_OUTBOUND_TUNNEL_LENGTH)); + const int _INBOUND_TUNNELS_QUANTITY = DEFAULT_INBOUND_TUNNELS_QUANTITY; + param.setInbound_quantity( QString::number(_INBOUND_TUNNELS_QUANTITY)); + const int _OUTBOUND_TUNNELS_QUANTITY = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; + param.setOutbound_quantity(QString::number(_OUTBOUND_TUNNELS_QUANTITY)); + const int _TAGS_TO_SEND = DEFAULT_TAGS_TO_SEND; + param.setCrypto_tagsToSend(QString::number(_TAGS_TO_SEND)); + const int _i2cp_leaseSetAuthType = 0; + param.set_i2cp_leaseSetAuthType(QString::number(_i2cp_leaseSetAuthType)); + const QString _i2cp_leaseSetEncType = "0,4"; //todo Identity's type by default + param.set_i2cp_leaseSetEncType(_i2cp_leaseSetEncType); + param.set_i2cp_leaseSetPrivKey(""); + const int _i2cp_leaseSetType = DEFAULT_LEASESET_TYPE; + param.set_i2cp_leaseSetType(QString::number(_i2cp_leaseSetType)); + bool _i2p_streaming_answerPings= DEFAULT_ANSWER_PINGS; + param.set_i2p_streaming_answerPings(_i2p_streaming_answerPings); + const int _i2p_streaming_initialAckDelay = DEFAULT_INITIAL_ACK_DELAY; + param.set_i2p_streaming_initialAckDelay(QString::number(_i2p_streaming_initialAckDelay)); + } + + + void DeleteTunnelNamed(std::string name) { + std::map::const_iterator it=tunnelConfigs.find(name); + if(it!=tunnelConfigs.end()){ + TunnelConfig* tc=it->second; + deleteTunnelFromUI(name, tc); + tunnelConfigs.erase(it); + delete tc; + } + saveAllConfigs(true, FocusEnum::noFocus); + } + + std::string GenerateNewTunnelName() { + int i=1; + while(true){ + std::stringstream name; + name << "name" << i; + const std::string& str=name.str(); + if(tunnelConfigs.find(str)==tunnelConfigs.end())return str; + ++i; + } + } + + void CreateDefaultClientTunnel() {//TODO dedup default values with ReadTunnelsConfig() and with ClientContext.cpp::ReadTunnels () + std::string name=GenerateNewTunnelName(); + std::string type = I2P_TUNNELS_SECTION_TYPE_CLIENT; + std::string dest = "127.0.0.1"; + int port = 0; + std::string keys = ""; + std::string address = "127.0.0.1"; + int destinationPort = 0; + int cryptoType = 0; + i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256; + // I2CP + I2CPParameters i2cpParameters; + CreateDefaultI2CPOptions (i2cpParameters); + + tunnelConfigs[name]=new ClientTunnelConfig(name, QString(type.c_str()), i2cpParameters, + dest, + port, + keys, + address, + destinationPort, + sigType, + cryptoType); + + saveAllConfigs(true, FocusEnum::focusOnTunnelName, name); + } + + void CreateDefaultServerTunnel() {//TODO dedup default values with ReadTunnelsConfig() and with ClientContext.cpp::ReadTunnels () + std::string name=GenerateNewTunnelName(); + std::string type=I2P_TUNNELS_SECTION_TYPE_SERVER; + std::string host = "127.0.0.1"; + int port = 0; + std::string keys = ""; + int inPort = 0; + std::string accessList = ""; + std::string hostOverride = ""; + std::string webircpass = ""; + bool gzip = true; + i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256; + std::string address = "127.0.0.1"; + bool isUniqueLocal = true; + int cryptoType = 0; + + // I2CP + I2CPParameters i2cpParameters; + CreateDefaultI2CPOptions (i2cpParameters); + + tunnelConfigs[name]=new ServerTunnelConfig(name, QString(type.c_str()), i2cpParameters, + host, + port, + keys, + inPort, + accessList, + hostOverride, + webircpass, + gzip, + sigType, + address, + isUniqueLocal, + cryptoType); + + + saveAllConfigs(true, FocusEnum::focusOnTunnelName, name); + } + + void ReadTunnelsConfig() //TODO deduplicate the code with ClientContext.cpp::ReadTunnels () + { + boost::property_tree::ptree pt; + std::string tunConf=tunconfpath.toStdString(); + if (tunConf == "") { + // TODO: cleanup this in 2.8.0 + tunConf = i2p::fs::DataDirPath ("tunnels.cfg"); + if (i2p::fs::Exists(tunConf)) { + LogPrint(eLogWarning, "FS: please rename tunnels.cfg -> tunnels.conf here: ", tunConf); + } else { + tunConf = i2p::fs::DataDirPath ("tunnels.conf"); + } + } + LogPrint(eLogDebug, "tunnels config file: ", tunConf); + try + { + boost::property_tree::read_ini (tunConf, pt); + } + catch (std::exception& ex) + { + LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());//TODO show err box and disable tunn.page + return; + } + + for (auto& section: pt) + { + std::string name = section.first; + try + { + std::string type = section.second.get (I2P_TUNNELS_SECTION_TYPE); + if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT + || type == I2P_TUNNELS_SECTION_TYPE_SOCKS + || type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS + || type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY + || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) + { + // mandatory params + std::string dest; + if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { + dest = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION); + } + int port = section.second.get (I2P_CLIENT_TUNNEL_PORT); + // optional params + std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, ""); + std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); + int cryptoType = section.second.get(I2P_CLIENT_TUNNEL_CRYPTO_TYPE, 0); + int destinationPort = section.second.get(I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); + i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); + // I2CP + std::map options; + I2CPParameters i2cpParameters; + ReadI2CPOptions (section, options, i2cpParameters); + + tunnelConfigs[name]=new ClientTunnelConfig(name, QString(type.c_str()), i2cpParameters, + dest, + port, + keys, + address, + destinationPort, + sigType, + cryptoType); + } + else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER + || type == I2P_TUNNELS_SECTION_TYPE_HTTP + || type == I2P_TUNNELS_SECTION_TYPE_IRC + || type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) + { + // mandatory params + std::string host = section.second.get (I2P_SERVER_TUNNEL_HOST); + int port = section.second.get (I2P_SERVER_TUNNEL_PORT); + // optional params + std::string keys = section.second.get (I2P_SERVER_TUNNEL_KEYS, ""); + int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0); + std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, ""); + std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, ""); + std::string webircpass = section.second.get (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); + bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); + i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); + bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); + int cryptoType = section.second.get(I2P_CLIENT_TUNNEL_CRYPTO_TYPE, 0); + + // I2CP + std::map options; + I2CPParameters i2cpParameters; + ReadI2CPOptions (section, options, i2cpParameters); + + /* + std::set idents; + if (accessList.length () > 0) + { + size_t pos = 0, comma; + do + { + comma = accessList.find (',', pos); + i2p::data::IdentHash ident; + ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); + idents.insert (ident); + pos = comma + 1; + } + while (comma != std::string::npos); + } + */ + tunnelConfigs[name]=new ServerTunnelConfig(name, QString(type.c_str()), i2cpParameters, + host, + port, + keys, + inPort, + accessList, + hostOverride, + webircpass, + gzip, + sigType, + address, + isUniqueLocal, + cryptoType); + } + else + LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);//TODO show err box and disable the tunn gui + + } + catch (std::exception& ex) + { + LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());//TODO show err box and disable the tunn gui + } + } + } + +private: + class TunnelsPageUpdateListenerMainWindowImpl : public TunnelsPageUpdateListener { + MainWindow* mainWindow; + public: + TunnelsPageUpdateListenerMainWindowImpl(MainWindow* mainWindow_):mainWindow(mainWindow_){} + virtual void updated(std::string oldName, TunnelConfig* tunConf); + virtual void needsDeleting(std::string oldName); + }; + + TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener; + + //void onLoggingOptionsChange() {} + + SaverImpl* saverPtr; +}; + +#endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui new file mode 100644 index 0000000..8f942b0 --- /dev/null +++ b/src/mainwindow.ui @@ -0,0 +1,1053 @@ + + + MainWindow + + + + 0 + 0 + 908 + 604 + + + + + 908 + 0 + + + + + 908 + 16777215 + + + + MainWindow + + + + + 0 + 0 + + + + + 908 + 600 + + + + + 908 + 600 + + + + + + 10 + 10 + 888 + 596 + + + + + QLayout::SetMaximumSize + + + + + QLayout::SetMinimumSize + + + + 0 + 0 + 170 + 596 + + + + + + true + + + Status + + + + + + + + 0 + 0 + + + + + 172 + 0 + + + + + + + + Log + + + + + + + true + + + General settings + + + + + + + true + + + Tunnels settings + + + + + + + true + + + Restart + + + + + + + true + + + Quit + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 171 + 0 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 9 + + + + Qt::NoContextMenu + + + Show app name, version and build date + + + <html><head/><body><p><a href="about:i2pd_qt"><span style="text-decoration: none; color:#a0a0a0;"><span style="font-weight: 500;">i2pd_qt</span><br/>Version SHORT_VERSION · About...</span></a></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 6 + + + 0 + + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + 0 + 30 + + + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + wrongInputMessageLabel + + + true + + + 10 + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 707 + 713 + + + + 1 + + + + + 0 + 0 + + + + + + 0 + 0 + 707 + 586 + + + + + QLayout::SetMaximumSize + + + + + + 15 + + + + Status + + + + + + + QLayout::SetMaximumSize + + + + + + + + + + 0 + 0 + + + + + + 0 + 0 + 707 + 586 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Log + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + 10000 + + + false + + + true + + + + + + + + + + 0 + 0 + + + + + + 0 + 0 + 707 + 586 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + General settings + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + + + 0 + 0 + 693 + 498 + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + 707 + 586 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Tunnels settings + + + + + + + + + Add Client Tunnel + + + + + + + Add Server Tunnel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::ScrollBarAlwaysOn + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 699 + 425 + + + + + + + + + + + + + 0 + 0 + 707 + 586 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Restart + + + + + + + Restart i2pd + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 0 + + + + + + 0 + 0 + 707 + 531 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Quit + + + + + + + Quit Now + + + + + + + Graceful Quit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + + handleQuitButton() + handleGracefulQuitButton() + + diff --git a/src/pagewithbackbutton.cpp b/src/pagewithbackbutton.cpp new file mode 100644 index 0000000..bc297ac --- /dev/null +++ b/src/pagewithbackbutton.cpp @@ -0,0 +1,24 @@ +#include "pagewithbackbutton.h" +#include "QVBoxLayout" +#include "QHBoxLayout" +#include "QPushButton" + +PageWithBackButton::PageWithBackButton(QWidget *parent, QWidget* child) : QWidget(parent) +{ + QVBoxLayout * layout = new QVBoxLayout(); + setLayout(layout); + QWidget * topBar = new QWidget(); + QHBoxLayout * topBarLayout = new QHBoxLayout(); + topBar->setLayout(topBarLayout); + layout->addWidget(topBar); + layout->addWidget(child); + + QPushButton * backButton = new QPushButton(topBar); + backButton->setText("< Back"); + topBarLayout->addWidget(backButton); + connect(backButton, SIGNAL(released()), this, SLOT(backReleasedSlot())); +} + +void PageWithBackButton::backReleasedSlot() { + emit backReleased(); +} diff --git a/src/pagewithbackbutton.h b/src/pagewithbackbutton.h new file mode 100644 index 0000000..60779f8 --- /dev/null +++ b/src/pagewithbackbutton.h @@ -0,0 +1,21 @@ +#ifndef PAGEWITHBACKBUTTON_H +#define PAGEWITHBACKBUTTON_H + +#include + +class PageWithBackButton : public QWidget +{ + Q_OBJECT +public: + explicit PageWithBackButton(QWidget *parent, QWidget* child); + +signals: + + void backReleased(); + +private slots: + + void backReleasedSlot(); +}; + +#endif // PAGEWITHBACKBUTTON_H diff --git a/src/resources/icons/mask.ico b/src/resources/icons/mask.ico new file mode 100644 index 0000000000000000000000000000000000000000..f5807de5ccae7dae7b7234badc651a7a57b62367 GIT binary patch literal 156564 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%0AO>91EHxccO^29Yysmoh8MthpVdk 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%0A2cpAh53rB_uKqdNWrzK_ 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 K0(OBOy!U^N3-aIq literal 0 HcmV?d00001 diff --git a/src/resources/images/icon.png b/src/resources/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a5dc7b680ba9dee30161ffb1c9fcd17bbd6ddd84 GIT binary patch literal 8712 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 literal 0 HcmV?d00001 diff --git a/src/routercommandswidget.ui b/src/routercommandswidget.ui new file mode 100644 index 0000000..f95db1f --- /dev/null +++ b/src/routercommandswidget.ui @@ -0,0 +1,127 @@ + + + routerCommandsWidget + + + + 0 + 0 + 707 + 300 + + + + + 0 + 0 + + + + Form + + + + + 0 + 0 + 707 + 301 + + + + + QLayout::SetMaximumSize + + + + + + 0 + 0 + + + + + 75 + true + + + + Router Commands + + + + + + + + 0 + 0 + + + + Run peer test + + + + + + + + 0 + 0 + + + + Decline transit tunnels + + + + + + + + 0 + 0 + + + + Accept transit tunnels + + + + + + + false + + + + 0 + 0 + + + + Cancel graceful quit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + diff --git a/src/statusbuttons.ui b/src/statusbuttons.ui new file mode 100644 index 0000000..edf5a90 --- /dev/null +++ b/src/statusbuttons.ui @@ -0,0 +1,163 @@ + + + StatusButtonsForm + + + + 0 + 0 + 171 + 295 + + + + + 0 + 0 + + + + + 171 + 295 + + + + Form + + + + + 21 + 0 + 171 + 300 + + + + + QLayout::SetDefaultConstraint + + + + + + 150 + 16777215 + + + + Main page + + + + + + + + 150 + 16777215 + + + + Router commands + + + + + + + + 150 + 16777215 + + + + Local destinations + + + + + + + + 150 + 16777215 + + + + Leasesets + + + + + + + + 150 + 16777215 + + + + Tunnels + + + + + + + + 150 + 16777215 + + + + Transit tunnels + + + + + + + + 150 + 16777215 + + + + Transports + + + + + + + + 150 + 16777215 + + + + I2P tunnels + + + + + + + + 150 + 16777215 + + + + SAM sessions + + + + + + + + + diff --git a/src/textbrowsertweaked1.cpp b/src/textbrowsertweaked1.cpp new file mode 100644 index 0000000..f880206 --- /dev/null +++ b/src/textbrowsertweaked1.cpp @@ -0,0 +1,9 @@ +#include "textbrowsertweaked1.h" + +TextBrowserTweaked1::TextBrowserTweaked1(QWidget * parent): QTextBrowser(parent) +{ +} + +/*void TextBrowserTweaked1::setSource(const QUrl & url) { + emit navigatedTo(url); +}*/ diff --git a/src/textbrowsertweaked1.h b/src/textbrowsertweaked1.h new file mode 100644 index 0000000..288a3c3 --- /dev/null +++ b/src/textbrowsertweaked1.h @@ -0,0 +1,26 @@ +#ifndef TEXTBROWSERTWEAKED1_H +#define TEXTBROWSERTWEAKED1_H + +#include +#include + +class TextBrowserTweaked1 : public QTextBrowser +{ + Q_OBJECT + +public: + TextBrowserTweaked1(QWidget * parent); + //virtual void setSource(const QUrl & url); + +signals: + void mouseReleased(); + //void navigatedTo(const QUrl & link); + +protected: + void mouseReleaseEvent(QMouseEvent *event) { + QTextBrowser::mouseReleaseEvent(event); + emit mouseReleased(); + } +}; + +#endif // TEXTBROWSERTWEAKED1_H diff --git a/src/tunnelform.ui b/src/tunnelform.ui new file mode 100644 index 0000000..61e5477 --- /dev/null +++ b/src/tunnelform.ui @@ -0,0 +1,104 @@ + + + Form + + + + 0 + 0 + 527 + 452 + + + + Form + + + + + 0 + 0 + 521 + 451 + + + + + + + server_tunnel_name + + + + + 0 + 20 + 511 + 421 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete + + + + + + + + + + + Host: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + diff --git a/src/widgetlock.cpp b/src/widgetlock.cpp new file mode 100644 index 0000000..a601fb3 --- /dev/null +++ b/src/widgetlock.cpp @@ -0,0 +1 @@ +#include "widgetlock.h" diff --git a/src/widgetlock.h b/src/widgetlock.h new file mode 100644 index 0000000..5b21125 --- /dev/null +++ b/src/widgetlock.h @@ -0,0 +1,35 @@ +#ifndef WIDGETLOCK_H +#define WIDGETLOCK_H + +#include +#include +#include +#include + +class widgetlock : public QObject { + Q_OBJECT + +private: + QWidget* widget; + QPushButton* lockButton; + +public slots: + void lockButtonClicked(bool) { + bool wasEnabled = widget->isEnabled(); + widget->setEnabled(!wasEnabled); + lockButton->setText(widget->isEnabled()?lockButton->tr("Lock"):lockButton->tr("Edit")); + } + +public: + widgetlock(QWidget* widget_, QPushButton* lockButton_): widget(widget_),lockButton(lockButton_) { + widget->setEnabled(false); + lockButton->setText(lockButton->tr("Edit")); + QObject::connect(lockButton,SIGNAL(clicked(bool)), this, SLOT(lockButtonClicked(bool))); + } + virtual ~widgetlock() {} + void deleteListener() { + QObject::disconnect(lockButton,SIGNAL(clicked(bool)), this, SLOT(lockButtonClicked(bool))); + } +}; + +#endif // WIDGETLOCK_H diff --git a/src/widgetlockregistry.cpp b/src/widgetlockregistry.cpp new file mode 100644 index 0000000..0d66d32 --- /dev/null +++ b/src/widgetlockregistry.cpp @@ -0,0 +1,2 @@ +#include "widgetlockregistry.h" + diff --git a/src/widgetlockregistry.h b/src/widgetlockregistry.h new file mode 100644 index 0000000..78ee142 --- /dev/null +++ b/src/widgetlockregistry.h @@ -0,0 +1,27 @@ +#ifndef WIDGETLOCKREGISTRY_H +#define WIDGETLOCKREGISTRY_H + +#include +#include + +class widgetlockregistry { + std::vector locks; + +public: + widgetlockregistry() : locks() {} + virtual ~widgetlockregistry() {} + void add(widgetlock* lock) { + locks.push_back(lock); + } + + void deleteListeners() { + while(!locks.empty()) { + widgetlock* lock = locks.back(); + lock->deleteListener(); + delete lock; + locks.pop_back(); + } + } +}; + +#endif // WIDGETLOCKREGISTRY_H