We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

Commit 47034553 authored by Brenda Wallace's avatar Brenda Wallace

Merge commit 'mainline/0.9.x' into 0.9.x

parents c89ed16d 9653cb9f
......@@ -126,6 +126,8 @@ class OtpAction extends Action
$this->lt->delete();
$this->lt = null;
common_real_login(true);
if ($this->rememberme) {
common_rememberme($this->user);
}
......
......@@ -55,7 +55,7 @@ class User_username extends Memcached_DataObject
// now define the keys.
function keys() {
return array('provider_name', 'username');
return array('provider_name' => 'K', 'username' => 'K');
}
}
......@@ -124,6 +124,8 @@ $config['sphinx']['port'] = 3312;
// Email info, used for all outbound email
// $config['mail']['notifyfrom'] = 'microblog@example.net';
// Domain for generating no-reply and incoming email addresses, if enabled.
// Defaults to site server name.
// $config['mail']['domain'] = 'microblog.example.net';
// See http://pear.php.net/manual/en/package.mail.mail.factory.php for options
// $config['mail']['backend'] = 'smtp';
......@@ -131,8 +133,6 @@ $config['sphinx']['port'] = 3312;
// 'host' => 'localhost',
// 'port' => 25,
// );
// For incoming email, if enabled. Defaults to site server name.
// $config['mail']['domain'] = 'incoming.example.net';
// exponential decay factor for tags, default 10 days
// raise this if traffic is slow, lower it if it's fast
......
......@@ -301,6 +301,19 @@ function checkPrereqs()
$pass = false;
}
// Look for known library bugs
$str = "abcdefghijklmnopqrstuvwxyz";
$replaced = preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str);
if ($str != $replaced) {
printf('<p class="error">PHP is linked to a version of the PCRE library ' .
'that does not support Unicode properties. ' .
'If you are running Red Hat Enterprise Linux / ' .
'CentOS 5.4 or earlier, see <a href="' .
'http://status.net/wiki/Red_Hat_Enterprise_Linux#PCRE_library' .
'">our documentation page</a> on fixing this.</p>');
$pass = false;
}
$reqs = array('gd', 'curl',
'xmlwriter', 'mbstring', 'xml', 'dom', 'simplexml');
......@@ -470,6 +483,7 @@ function showForm()
$dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
}
}
echo<<<E_O_T
</ul>
</dd>
......@@ -546,6 +560,11 @@ function showForm()
<input id="admin_email" name="admin_email" value="{$post->value('admin_email')}" />
<p class="form_guide">Optional email address for the initial StatusNet user (administrator)</p>
</li>
<li>
<label for="admin_updates">Subscribe to announcements</label>
<input type="checkbox" id="admin_updates" name="admin_updates" value="true" checked="checked" />
<p class="form_guide">Release and security feed from <a href="http://update.status.net/">update@status.net</a> (recommended)</p>
</li>
</ul>
</fieldset>
<input type="submit" name="submit" class="submit" value="Submit" />
......@@ -570,10 +589,11 @@ function handlePost()
$sitename = $_POST['sitename'];
$fancy = !empty($_POST['fancy']);
$adminNick = $_POST['admin_nickname'];
$adminNick = strtolower($_POST['admin_nickname']);
$adminPass = $_POST['admin_password'];
$adminPass2 = $_POST['admin_password2'];
$adminEmail = $_POST['admin_email'];
$adminUpdates = $_POST['admin_updates'];
$server = $_SERVER['HTTP_HOST'];
$path = substr(dirname($_SERVER['PHP_SELF']), 1);
......@@ -610,6 +630,19 @@ STR;
updateStatus("No initial StatusNet user nickname specified.", true);
$fail = true;
}
if ($adminNick && !preg_match('/^[0-9a-z]{1,64}$/', $adminNick)) {
updateStatus('The user nickname "' . htmlspecialchars($adminNick) .
'" is invalid; should be plain letters and numbers no longer than 64 characters.', true);
$fail = true;
}
// @fixme hardcoded list; should use User::allowed_nickname()
// if/when it's safe to have loaded the infrastructure here
$blacklist = array('main', 'admin', 'twitter', 'settings', 'rsd.xml', 'favorited', 'featured', 'favoritedrss', 'featuredrss', 'rss', 'getfile', 'api', 'groups', 'group', 'peopletag', 'tag', 'user', 'message', 'conversation', 'bookmarklet', 'notice', 'attachment', 'search', 'index.php', 'doc', 'opensearch', 'robots.txt', 'xd_receiver.html', 'facebook');
if (in_array($adminNick, $blacklist)) {
updateStatus('The user nickname "' . htmlspecialchars($adminNick) .
'" is reserved.', true);
$fail = true;
}
if (empty($adminPass)) {
updateStatus("No initial StatusNet user password specified.", true);
......@@ -644,7 +677,7 @@ STR;
}
// Okay, cross fingers and try to register an initial user
if (registerInitialUser($adminNick, $adminPass, $adminEmail)) {
if (registerInitialUser($adminNick, $adminPass, $adminEmail, $adminUpdates)) {
updateStatus(
"An initial user with the administrator role has been created."
);
......@@ -841,7 +874,7 @@ function runDbScript($filename, $conn, $type = 'mysqli')
return true;
}
function registerInitialUser($nickname, $password, $email)
function registerInitialUser($nickname, $password, $email, $adminUpdates)
{
define('STATUSNET', true);
define('LACONICA', true); // compatibility
......@@ -869,7 +902,7 @@ function registerInitialUser($nickname, $password, $email)
// Attempt to do a remote subscribe to update@status.net
// Will fail if instance is on a private network.
if (class_exists('Ostatus_profile')) {
if (class_exists('Ostatus_profile') && $adminUpdates) {
try {
$oprofile = Ostatus_profile::ensureProfile('http://update.status.net/');
Subscription::start($user->getProfile(), $oprofile->localProfile());
......
......@@ -235,7 +235,11 @@ class ApiAuthAction extends ApiAction
{
$this->basicAuthProcessHeader();
$realm = common_config('site', 'name') . ' API';
$realm = common_config('api', 'realm');
if (empty($realm)) {
$realm = common_config('site', 'name') . ' API';
}
if (!isset($this->auth_user_nickname) && $required) {
header('WWW-Authenticate: Basic realm="' . $realm . '"');
......
......@@ -47,6 +47,25 @@ class Channel
}
}
class CLIChannel extends Channel
{
function source()
{
return 'cli';
}
function output($user, $text)
{
$site = common_config('site', 'name');
print "[{$user->nickname}@{$site}] $text\n";
}
function error($user, $text)
{
$this->output($user, $text);
}
}
class XMPPChannel extends Channel
{
......
This diff is collapsed.
......@@ -294,4 +294,6 @@ $default =
array('crawldelay' => 0,
'disallow' => array('main', 'settings', 'admin', 'search', 'message')
),
'api' =>
array('realm' => null),
);
......@@ -88,22 +88,30 @@ class Sharing_XMPP extends XMPPHP_XMPP
/**
* Build an XMPP proxy connection that'll save outgoing messages
* to the 'xmppout' queue to be picked up by xmppdaemon later.
*
* If queueing is disabled, we'll grab a live connection.
*
* @return XMPPHP
*/
function jabber_proxy()
{
$proxy = new Queued_XMPP(common_config('xmpp', 'host') ?
common_config('xmpp', 'host') :
common_config('xmpp', 'server'),
common_config('xmpp', 'port'),
common_config('xmpp', 'user'),
common_config('xmpp', 'password'),
common_config('xmpp', 'resource') . 'daemon',
common_config('xmpp', 'server'),
common_config('xmpp', 'debug') ?
true : false,
common_config('xmpp', 'debug') ?
XMPPHP_Log::LEVEL_VERBOSE : null);
return $proxy;
if (common_config('queue', 'enabled')) {
$proxy = new Queued_XMPP(common_config('xmpp', 'host') ?
common_config('xmpp', 'host') :
common_config('xmpp', 'server'),
common_config('xmpp', 'port'),
common_config('xmpp', 'user'),
common_config('xmpp', 'password'),
common_config('xmpp', 'resource') . 'daemon',
common_config('xmpp', 'server'),
common_config('xmpp', 'debug') ?
true : false,
common_config('xmpp', 'debug') ?
XMPPHP_Log::LEVEL_VERBOSE : null);
return $proxy;
} else {
return jabber_connect();
}
}
/**
......
......@@ -49,10 +49,20 @@ class Queued_XMPP extends XMPPHP_XMPP
*/
public function __construct($host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null)
{
parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel);
// Normally the fulljid isn't filled out until resource binding time;
// we need to save it here since we're not talking to a real server.
$this->fulljid = "{$this->basejid}/{$this->resource}";
parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel);
// We use $host to connect, but $server to build JIDs if specified.
// This seems to fix an upstream bug where $host was used to build
// $this->basejid, never seen since it isn't actually used in the base
// classes.
if (!$server) {
$server = $this->host;
}
$this->basejid = $this->user . '@' . $server;
// Normally the fulljid is filled out by the server at resource binding
// time, but we need to do it since we're not talking to a real server.
$this->fulljid = "{$this->basejid}/{$this->resource}";
}
/**
......
......@@ -342,7 +342,11 @@ class StatusNet
if (array_key_exists('memcached', $config)) {
if ($config['memcached']['enabled']) {
addPlugin('Memcache', array('servers' => $config['memcached']['server']));
if(class_exists('Memcached')) {
addPlugin('Memcached', array('servers' => $config['memcached']['server']));
} else {
addPlugin('Memcache', array('servers' => $config['memcached']['server']));
}
}
if (!empty($config['memcached']['base'])) {
......
......@@ -1462,7 +1462,15 @@ function common_copy_args($from)
$to = array();
$strip = get_magic_quotes_gpc();
foreach ($from as $k => $v) {
$to[$k] = ($strip) ? stripslashes($v) : $v;
if($strip) {
if(is_array($v)) {
$to[$k] = common_copy_args($v);
} else {
$to[$k] = stripslashes($v);
}
} else {
$to[$k] = $v;
}
}
return $to;
}
......
......@@ -36,6 +36,7 @@ class XmppManager extends IoManager
protected $site = null;
protected $pingid = 0;
protected $lastping = null;
protected $conn = null;
static protected $singletons = array();
......
......@@ -9,12 +9,12 @@ msgid ""
msgstr ""
"Project-Id-Version: StatusNet\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-04 18:55+0000\n"
"PO-Revision-Date: 2010-03-05 22:34:53+0000\n"
"POT-Creation-Date: 2010-03-06 23:49+0000\n"
"PO-Revision-Date: 2010-03-06 23:49:16+0000\n"
"Language-Team: Arabic\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: MediaWiki 1.17alpha (r63298); Translate extension (2010-01-16)\n"
"X-Generator: MediaWiki 1.17alpha (r63350); Translate extension (2010-01-16)\n"
"X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
"X-Language-Code: ar\n"
"X-Message-Group: out-statusnet\n"
......@@ -102,7 +102,7 @@ msgstr "لا صفحة كهذه"
#: actions/otp.php:76 actions/remotesubscribe.php:145
#: actions/remotesubscribe.php:154 actions/replies.php:73
#: actions/repliesrss.php:38 actions/rsd.php:116 actions/showfavorites.php:105
#: actions/userbyid.php:74 actions/usergroups.php:91 actions/userrss.php:38
#: actions/userbyid.php:74 actions/usergroups.php:91 actions/userrss.php:40
#: actions/xrds.php:71 lib/command.php:163 lib/command.php:302
#: lib/command.php:355 lib/command.php:401 lib/command.php:462
#: lib/command.php:518 lib/galleryaction.php:59 lib/mailbox.php:82
......@@ -549,7 +549,7 @@ msgstr ""
#: actions/apioauthauthorize.php:276
msgid "Allow or deny access"
msgstr ""
msgstr "اسمح أو امنع الوصول"
#: actions/apioauthauthorize.php:292
#, php-format
......@@ -681,7 +681,7 @@ msgstr "تكرارات %s"
msgid "Notices tagged with %s"
msgstr "الإشعارات الموسومة ب%s"
#: actions/apitimelinetag.php:104 actions/tagrss.php:64
#: actions/apitimelinetag.php:104 actions/tagrss.php:65
#, php-format
msgid "Updates tagged with %1$s on %2$s!"
msgstr ""
......@@ -721,7 +721,7 @@ msgstr "بإمكانك رفع أفتارك الشخصي. أقصى حجم للم
#: actions/avatarsettings.php:106 actions/avatarsettings.php:185
#: actions/remotesubscribe.php:191 actions/userauthorization.php:72
#: actions/userrss.php:103
#: actions/userrss.php:106
msgid "User without matching profile"
msgstr ""
......@@ -1691,7 +1691,7 @@ msgstr ""
msgid "Make this user an admin"
msgstr "اجعل هذا المستخدم إداريًا"
#: actions/grouprss.php:138 actions/userrss.php:90
#: actions/grouprss.php:138 actions/userrss.php:93
#: lib/atomgroupnoticefeed.php:61 lib/atomusernoticefeed.php:67
#, php-format
msgid "%s timeline"
......@@ -2353,7 +2353,7 @@ msgstr "كلمة السر القديمة"
#: actions/passwordsettings.php:108 actions/recoverpassword.php:235
msgid "New password"
msgstr "كلمة سر جديدة"
msgstr "كلمة السر الجديدة"
#: actions/passwordsettings.php:109
msgid "6 or more characters"
......@@ -4229,7 +4229,7 @@ msgstr "%s ليس عضوًا في أي مجموعة."
msgid "Try [searching for groups](%%action.groupsearch%%) and joining them."
msgstr ""
#: actions/userrss.php:92 lib/atomgroupnoticefeed.php:66
#: actions/userrss.php:95 lib/atomgroupnoticefeed.php:66
#: lib/atomusernoticefeed.php:72
#, php-format
msgid "Updates from %1$s on %2$s!"
......@@ -4486,10 +4486,9 @@ msgstr "الصفحة الشخصية"
#. TRANS: Tooltip for main menu option "Account"
#: lib/action.php:435
#, fuzzy
msgctxt "TOOLTIP"
msgid "Change your email, avatar, password, profile"
msgstr "غير كلمة سرّك"
msgstr "غير بريدك الإلكتروني وكلمة سرّك وأفتارك وملفك الشخصي"
#. TRANS: Tooltip for main menu option "Services"
#: lib/action.php:440
......@@ -4977,12 +4976,12 @@ msgstr "%s ترك المجموعة %s"
msgid "Fullname: %s"
msgstr "الاسم الكامل: %s"
#: lib/command.php:312 lib/mail.php:254
#: lib/command.php:312 lib/mail.php:258
#, php-format
msgid "Location: %s"
msgstr "الموقع: %s"
#: lib/command.php:315 lib/mail.php:256
#: lib/command.php:315 lib/mail.php:260
#, php-format
msgid "Homepage: %s"
msgstr "الصفحة الرئيسية: %s"
......@@ -5042,9 +5041,8 @@ msgid "Specify the name of the user to subscribe to"
msgstr ""
#: lib/command.php:554 lib/command.php:589
#, fuzzy
msgid "No such user"
msgstr "لا مستخدم كهذا."
msgstr "لا مستخدم كهذا"
#: lib/command.php:561
#, php-format
......@@ -5427,11 +5425,11 @@ msgstr "لُج باسم مستخدم وكلمة سر"
msgid "Sign up for a new account"
msgstr "سجّل حسابًا جديدًا"
#: lib/mail.php:172
#: lib/mail.php:173
msgid "Email address confirmation"
msgstr "تأكيد عنوان البريد الإلكتروني"
#: lib/mail.php:174
#: lib/mail.php:175
#, php-format
msgid ""
"Hey, %s.\n"
......@@ -5447,13 +5445,25 @@ msgid ""
"Thanks for your time, \n"
"%s\n"
msgstr ""
"مرحبًا، %s.\n"
"\n"
"لقد أدخل أحدهم قبل لحظات عنوان البريد الإلكتروني هذا على %s.\n"
"\n"
"إذا كنت هو، وإذا كنت تريد تأكيد هذه المدخلة، فاستخدم المسار أدناه:\n"
"\n"
" %s\n"
"\n"
"إذا كان الأمر خلاف ذلك، فتجاهل هذه الرسالة.\n"
"\n"
"شكرًا على الوقت الذي أمضيته، \n"
"%s\n"
#: lib/mail.php:236
#: lib/mail.php:240
#, php-format
msgid "%1$s is now listening to your notices on %2$s."
msgstr "%1$s يستمع الآن إلى إشعاراتك على %2$s."
#: lib/mail.php:241
#: lib/mail.php:245
#, php-format
msgid ""
"%1$s is now listening to your notices on %2$s.\n"
......@@ -5478,17 +5488,17 @@ msgstr ""
"----\n"
"غيّر خيارات البريد الإلكتروني والإشعار في %8$s\n"
#: lib/mail.php:258
#: lib/mail.php:262
#, php-format
msgid "Bio: %s"
msgstr "السيرة: %s"
#: lib/mail.php:286
#: lib/mail.php:290
#, php-format
msgid "New email address for posting to %s"
msgstr "عنوان بريد إلكتروني جديد للإرسال إلى %s"
#: lib/mail.php:289
#: lib/mail.php:293
#, php-format
msgid ""
"You have a new posting address on %1$s.\n"
......@@ -5501,21 +5511,21 @@ msgid ""
"%4$s"
msgstr ""
#: lib/mail.php:413
#: lib/mail.php:417
#, php-format
msgid "%s status"
msgstr "حالة %s"
#: lib/mail.php:439
#: lib/mail.php:443
msgid "SMS confirmation"
msgstr "تأكيد الرسالة القصيرة"
#: lib/mail.php:463
#: lib/mail.php:467
#, php-format
msgid "You've been nudged by %s"
msgstr "لقد نبهك %s"
#: lib/mail.php:467
#: lib/mail.php:471
#, php-format
msgid ""
"%1$s (%2$s) is wondering what you are up to these days and is inviting you "
......@@ -5531,12 +5541,12 @@ msgid ""
"%4$s\n"
msgstr ""
#: lib/mail.php:510
#: lib/mail.php:517
#, php-format
msgid "New private message from %s"
msgstr "رسالة خاصة جديدة من %s"
#: lib/mail.php:514
#: lib/mail.php:521
#, php-format
msgid ""
"%1$s (%2$s) sent you a private message:\n"
......@@ -5555,12 +5565,12 @@ msgid ""
"%5$s\n"
msgstr ""
#: lib/mail.php:559
#: lib/mail.php:568
#, php-format
msgid "%s (@%s) added your notice as a favorite"
msgstr "لقد أضاف %s (@%s) إشعارك إلى مفضلاته"
#: lib/mail.php:561
#: lib/mail.php:570
#, php-format
msgid ""
"%1$s (@%7$s) just added your notice from %2$s as one of their favorites.\n"
......@@ -5581,12 +5591,12 @@ msgid ""
"%6$s\n"
msgstr ""
#: lib/mail.php:624
#: lib/mail.php:635
#, php-format
msgid "%s (@%s) sent a notice to your attention"
msgstr "لقد أرسل %s (@%s) إشعارًا إليك"
#: lib/mail.php:626
#: lib/mail.php:637
#, php-format
msgid ""
"%1$s (@%9$s) just sent a notice to your attention (an '@-reply') on %2$s.\n"
......
......@@ -10,12 +10,12 @@ msgid ""
msgstr ""
"Project-Id-Version: StatusNet\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-04 18:55+0000\n"
"PO-Revision-Date: 2010-03-05 22:34:56+0000\n"
"POT-Creation-Date: 2010-03-06 23:49+0000\n"
"PO-Revision-Date: 2010-03-06 23:49:19+0000\n"
"Language-Team: Egyptian Spoken Arabic\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: MediaWiki 1.17alpha (r63298); Translate extension (2010-01-16)\n"
"X-Generator: MediaWiki 1.17alpha (r63350); Translate extension (2010-01-16)\n"
"X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
"X-Language-Code: arz\n"
"X-Message-Group: out-statusnet\n"
......@@ -108,7 +108,7 @@ msgstr "لا صفحه كهذه"
#: actions/otp.php:76 actions/remotesubscribe.php:145
#: actions/remotesubscribe.php:154 actions/replies.php:73
#: actions/repliesrss.php:38 actions/rsd.php:116 actions/showfavorites.php:105
#: actions/userbyid.php:74 actions/usergroups.php:91 actions/userrss.php:38
#: actions/userbyid.php:74 actions/usergroups.php:91 actions/userrss.php:40
#: actions/xrds.php:71 lib/command.php:163 lib/command.php:302
#: lib/command.php:355 lib/command.php:401 lib/command.php:462
#: lib/command.php:518 lib/galleryaction.php:59 lib/mailbox.php:82
......@@ -687,7 +687,7 @@ msgstr "تكرارات %s"
msgid "Notices tagged with %s"
msgstr "الإشعارات الموسومه ب%s"
#: actions/apitimelinetag.php:104 actions/tagrss.php:64
#: actions/apitimelinetag.php:104 actions/tagrss.php:65
#, php-format
msgid "Updates tagged with %1$s on %2$s!"
msgstr ""
......@@ -727,7 +727,7 @@ msgstr ""
#: actions/avatarsettings.php:106 actions/avatarsettings.php:185
#: actions/remotesubscribe.php:191 actions/userauthorization.php:72
#: actions/userrss.php:103
#: actions/userrss.php:106
msgid "User without matching profile"
msgstr ""
......@@ -1703,7 +1703,7 @@ msgstr ""
msgid "Make this user an admin"
msgstr "اجعل هذا المستخدم إداريًا"
#: actions/grouprss.php:138 actions/userrss.php:90
#: actions/grouprss.php:138 actions/userrss.php:93
#: lib/atomgroupnoticefeed.php:61 lib/atomusernoticefeed.php:67
#, php-format
msgid "%s timeline"
......@@ -4234,7 +4234,7 @@ msgstr ""
msgid "Try [searching for groups](%%action.groupsearch%%) and joining them."
msgstr ""
#: actions/userrss.php:92 lib/atomgroupnoticefeed.php:66
#: actions/userrss.php:95 lib/atomgroupnoticefeed.php:66
#: lib/atomusernoticefeed.php:72
#, php-format
msgid "Updates from %1$s on %2$s!"
......@@ -5002,12 +5002,12 @@ msgstr "%s ساب الجروپ %s"
msgid "Fullname: %s"
msgstr "الاسم الكامل: %s"
#: lib/command.php:312 lib/mail.php:254
#: lib/command.php:312 lib/mail.php:258
#, php-format
msgid "Location: %s"
msgstr "الموقع: %s"
#: lib/command.php:315 lib/mail.php:256
#: lib/command.php:315 lib/mail.php:260
#, php-format
msgid "Homepage: %s"
msgstr "الصفحه الرئيسية: %s"
......@@ -5452,11 +5452,11 @@ msgstr ""
msgid "Sign up for a new account"
msgstr ""
#: lib/mail.php:172
#: lib/mail.php:173
msgid "Email address confirmation"
msgstr "تأكيد عنوان البريد الإلكتروني"
#: lib/mail.php:174
#: lib/mail.php:175
#, php-format
msgid ""
"Hey, %s.\n"
......@@ -5473,12 +5473,12 @@ msgid ""
"%s\n"
msgstr ""
#: lib/mail.php:236
#: lib/mail.php:240
#, php-format
msgid "%1$s is now listening to your notices on %2$s."
msgstr ""
#: lib/mail.php:241
#: lib/mail.php:245
#, php-format
msgid ""
"%1$s is now listening to your notices on %2$s.\n"
......@@ -5493,17 +5493,17 @@ msgid ""
"Change your email address or notification options at %8$s\n"
msgstr ""
#: lib/mail.php:258
#: lib/mail.php:262
#, php-format
msgid "Bio: %s"
msgstr "عن نفسك: %s"